- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
当检测到距离小于1m的物体时,我试图通过仅打开LED来控制HC-SR4超声波传感器。
我将TIM2用于触发信号(引脚PB10),并将TIM4用于接收回波信号(引脚PB6)。 LED连接到PB7引脚。
当我加载下面的代码时,LED只是点亮,无论是否有物体,它都点亮。
知道我哪里出错了吗?
#include <stdio.h>
#include "stm32l1xx.h" // Keil::Device:Startup
// switch from HSE to HSI clock 16MHz
void HSI_config(){
RCC->CR |= RCC_CR_HSION; // Turn On HSI oscillator
RCC->CFGR |= RCC_CFGR_SW; // Select HSI clock
RCC->CFGR |= RCC_CFGR_SWS_HSI;
RCC->CR |= RCC_CR_HSIRDY; // wait for HSI stabilize
}
// Configure GPIO Port B
void GPIO_config(){
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOBRST; // Reset GPIOB clock
RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOBRST; // Clear Reset
RCC->AHBENR |= RCC_AHBENR_GPIOBEN; // Enable GPIOB clock
//PB6 Echo Pin
GPIOB->MODER &= ~(0x03 << (2*6)); // Clear bit 12 & 13 Alternate function mode
GPIOB->MODER |= 0x02 << (2*6); // set as Alternate function mode
GPIOB->OSPEEDR &= ~(0x03<< (2*6)); // 40 MHz speed
GPIOB->OSPEEDR |= 0x03<< (2*6); // 40 MHz speed
GPIOB->PUPDR &= ~(1<<6); // NO PULL-UP PULL-DOWN
GPIOB->OTYPER &= ~(1<<6); // PUSH-PULL
GPIOB->AFR[0] |= 0x2 << (4*6); // set PB pin 6 as AF2 (TIM4_CH1)
//PB10 Pluse Generating Pin
GPIOB->MODER &= ~(0x03 << (2*10)); // Clear bit 12 & 13 Alternate function mode
GPIOB->MODER |= 0x02 << (2*10); // set as Alternate function mode
GPIOB->OSPEEDR &= ~(0x03<< (2*10)); // 40 MHz speed
GPIOB->OSPEEDR |= 0x03<< (2*10); // 40 MHz speed
GPIOB->PUPDR &= ~(1<<10); // NO PULL-UP PULL-DOWN
GPIOB->OTYPER &= ~(1<<10); // PUSH-PULL
GPIOB->AFR[1] |= 0x1 << (4*2); // set PB pin 10 as AF1 (TIM2_CH3)
//PB7 LED ON/OFF
GPIOB->MODER |= GPIO_MODER_MODER7_0; // General purpose output mode
GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7; // Max High speed 50MHz
}
// CONFIGURE TIM4 FOR RECEIVING INPUT SIGNAL
void TIM4_Enable(){
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; // ENABLE TIM4 CLOCK
TIM4->PSC = 15; // SET APPROPRAIT PRESCALER TO SLOW DOWN THE CLOCK
TIM4->ARR = 0XFFFF; // SET MAX PULSE WIDTH OF 65536us FOR 16-BIT TIMER
TIM4->CCMR1 &= ~TIM_CCMR1_CC1S; // CLEAR CAPTURE/COMPARE REGISTER
TIM4->CCMR1 |= 0X1; // SELECT CH1 INPUTE CAPTURE
TIM4->CCMR1 &= ~TIM_CCMR1_IC1F; // DISABLE DIGITAL FILTERING
TIM4->CCER |= (1<<1 | 1<<3); // SELECT BOTH RISING AND FALLING EDGE DETECTION CC1P & CC1NP
TIM4->CCMR1 &= ~(TIM_CCMR1_IC1PSC); // INPUT PRESCALER 0 TO CAPTURE EACH VALID EDGE
TIM4->CCER |= TIM_CCER_CC1E; // ENABLE COUNTER CAPTURE
TIM4->DIER |= TIM_DIER_CC1IE; // ENABLE CH1 CAPTURE/COMPARE INTERRUPT
NVIC_SetPriority(TIM4_IRQn, 1); // SET PRIORITY TO 1
NVIC_EnableIRQ(TIM4_IRQn); //ENABLE TIM4 INTERRUPT IN NVIC
}
// CONFIGURE TIM2 FOR SENDING OUTPUT SIGNAL
void TIM2_Enable(){
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // ENABLE TIM2 CLOCK
TIM2->PSC = 15; // SET APPROPRAIT PRESCALER TO SLOW DOWN THE CLOCK
TIM2->ARR = 0XFFFF; // SET MAX PULSE WIDTH OF 65536us FOR 16-BIT TIMER
TIM2->CCMR2 |= TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2; // 111: PWM mode 1
TIM2->CCMR2 |= TIM_CCMR2_OC3PE; // CH3 Output Preload Enable
TIM2->CR1 |= TIM_CR1_ARPE; // Auto-reload Prelaod Enable
TIM2->CCER |= TIM_CCER_CC3E; // Enable Output for CH3
TIM2->EGR |= TIM_EGR_UG; // Force Update
TIM2->SR &= ~TIM_SR_UIF; // Clear the Update Flag
TIM2->DIER |= TIM_DIER_UIE; // Enable Interrupt on Update
TIM2->CR1 |= TIM_CR1_DIR; // Set downcounting counter direction
TIM2->CR1 |= TIM_CR1_CEN; // Enable Counter
}
//Initialize the float variables.
volatile uint8_t timespan = 0; // Total pulse width
volatile uint8_t lastcounter = 0; // Timer counter value of the last event
volatile uint8_t newcounter = 0; // Timer counter value of the current event
volatile uint8_t overflow = 0; // Count the number of overflows
volatile uint8_t PulseEnd = 0; // Declare end of pulse
void Echo_TIM4_IRQHandler(){
if ((TIM4->SR & TIM_SR_UIF) != 0){ // Check the update even flag
overflow = overflow + 1; // if UIF = 1, increment overflow counter
TIM4->SR &= ~TIM_SR_UIF; // clear UIF
}
if ((TIM4->SR & TIM_SR_CC1IF) != 0){ // Check capture event flag
newcounter = TIM4->CCR1; // read capture value, store as newcounter
timespan = (newcounter - lastcounter)+(65536 * overflow); // calculate the total pulse width
lastcounter = newcounter; // save the value of newcounter as lastcounter to be used for the next cycle
overflow = 0; // clear overflow counter
PulseEnd = 1;
}
}
void setSysTick(void){
// ---------- SysTick timer (1ms) -------- //
if (SysTick_Config(SystemCoreClock / 1000)) {
// Capture error
while (1){};
}
}
volatile uint32_t msTicks; //counts 1ms timeTicks
void SysTick_Handler(void) {
msTicks++;
}
static void Delay(__IO uint32_t dlyTicks){
uint32_t curTicks = msTicks;
while ((msTicks - curTicks) < dlyTicks);
}
int main(void){
float Distance = 0.0f; // actual distance in cm
int Pulsesent = 0;
HSI_config();
setSysTick();
GPIO_config();
TIM4_Enable();
Echo_TIM4_IRQHandler();
while(1){
if (Pulsesent == 0) {
(Pulsesent = 1);
TIM2_Enable();
}
if(Pulsesent && PulseEnd){
Pulsesent = 0;
if(overflow == 1){
timespan = 0;
}
else {
Distance = (timespan / 58) ;
}
Delay(1);
}
if (Distance <= 100){
GPIOB->BSRRL = (1<<7);
}
else {
GPIOB->BSRRL = (0<<7);
}
}
}
最佳答案
您的代码是一团糟,而不仅仅是布局,使用全局变量的“逻辑”似乎完全是foobar。我认为您必须付出巨大的努力来整理代码的设计,并从经验丰富的嵌入式软件工程师那里获得建议。想想:这只是一小段代码,您无法使其正常工作,因此,以当前的开发方法来开发复杂的工作方式-您需要更改方法。
与您的症状直接相关的代码问题中,至少有一个问题是,在PulseEnd
中直接调用TIM4中断处理程序时,全局变量之一main()
被设置为副作用-为什么? ?也许要初始化全局变量?不要这样! -并且永远不会在此代码的任何地方重置。
然后,第一次进入while(1)
循环,该循环立即将PulseSent
设置为1,测试if (PulseSent && PulseEnd)
当然是正确的,并且您的代码立即认为已检测到回声,而timespan
可能仍为0,当然小于5800(将timespan
除以随机的幻数58得到Distance
,然后将Distance
与100进行比较以决定LED应该亮还是灭)。但是,这不是唯一的问题,例如timespan
是uint8_t
,这意味着它是一个8位变量(类型名称中有提示),只能在0-255范围内,但是您尝试使用两个计时器计数器(可能为16位)之间的差值来填充timespan
,因为您会添加65536的可能溢出。因此,基本上,您的代码始终会立即认为存在小于100个单位距离的回声,此外距离永远不能超过255/58(4位),因此即使回声定时效果更好,也永远不能超过100,因此LED始终亮着。
不知道为什么有代码在overflow
中处理main()
,并且您正在同时修改main和TIM4 isr中的溢出是一个危险信号,闻到了潜在的神秘/短暂/稀有/不可追踪/致命的问题,我注意到,当overflow==1
时(但不是如果溢出> 1,并且由于TIM4中断代码正在递增而不能有效地溢出为1时,则不是),则不会重新计算Distance
,但随后的代码然后使用Distance
点亮/熄灭LED。这冒出更多的逻辑问题。newcounter
和lastcounter
也是uint8_t,但是计数器是16位的,不是吗?值得检查。您是否在启用警告的情况下运行编译器,应该能够告诉您何时必须通过赋值将表达式转换为限制性更强的类型(例如C192警告?)。如果没有警告,则应打开警告,并应注意它们。实际上,打开-Wall或任何等效的keil,并检查每个警告,最好通过更正代码来消除它。如果您无法更改代码以消除奇怪的警告。每次添加大量代码时,请确保检查警告中的更改。当然,最容易看到从零警告到> 0警告的变化,因此(也应该是)消除所有警告的另一个动机。
看不到任何代码可以处理没有回声响应的情况(如果超声波传感器损坏或断开连接,也可能发生)。好像您的代码(一旦PulseEnd问题解决了),如果没有得到回声,就永远不会再试一次,不确定。
由于PulseEnd永远不会重置,因此您的代码将尽快将TIM2脉冲发送到超声波测距仪-很好,延迟了delay(1),我猜这是一个1ms的延迟-因此,取决于硬件,尚不清楚实际上会得到回声响应。如果您查看了传感器的输出信号,您将会看到。
我已经确定了魔术数字58的来源,并假设TIM4以10KHz运行,空气中的声音速度为340m / s,到目标的距离为1m(因此脉冲必须传播2m)将花费5.882ms。好像您要通过将整数四舍五入为58.82来嵌入1.4%的比例缩放错误(在100cm的目标范围内为1.4 cm),如果计算必须为整数(但这不是因为Distance被声明为浮动)然后使用59只是0.3%的缩放误差,但您可以在浮点数中进行微不足道的计算,并且误差很小。我猜想存储在PSC中的幻数15会设置计时器速度。我讨厌魔术数字。
无论如何,当/如果您真的必须像这样在复杂的舞蹈中使用全局变量,请开发一个与其他人坐下来回顾您的工作并在纸上写出变量如何在初始化main()之间相互作用的过程。和中断例程,并要严格意识到,对它们处理方式的任何更改都意味着您需要坐下来并在一张新纸上重新演练该舞蹈,这是指它以前的工作方式,并将其记录在上一张纸上。并尽最大努力开发单元测试,至少可以让您有一定程度的信心,即对main()中的代码进行更改后,仍然有机会在接近您发现的真实硬件之前工作。很难理解实际情况。
关于c - HC-SR4超声波传感器与STM32L1接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45224559/
我正在尝试在我的代码库中为我正在编写的游戏服务器更多地使用接口(interface),并了解高级概念以及何时应该使用接口(interface)(我认为)。在我的例子中,我使用它们将我的包相互分离,并使
我有一个名为 Widget 的接口(interface),它在我的整个项目中都在使用。但是,它也用作名为 Widget 的组件的 Prop 。 处理此问题的最佳方法是什么?我应该更改我的 Widget
有一个接口(interface)可以是多个接口(interface)之一 interface a {x:string} interface b {y:string} interface c {z:st
我遇到了一种情况,我需要调用第三方服务来获取一些信息。这些服务对于不同的客户可能会有所不同。我的界面中有一个身份验证功能,如下所示。 interface IServiceProvider { bool
在我的例子中,“RequestHandlerProxy”是一个结构,其字段为接口(interface)“IAdapter”,接口(interface)有可能被调用的方法,该方法的输入为结构“Reque
我有一个接口(interface)Interface1,它已由类A实现,并且设置了一些私有(private)变量值,并且我将类A的对象发送到下一个接受输入作为Interface2的类。那么我怎样才能将
假设我有这样的类和接口(interface)结构: interface IService {} interface IEmailService : IService { Task SendAs
有人知道我在哪里可以找到 XML-RPC 接口(interface)的定义(在 OpenERP 7 中)?我想知道创建或获取对象需要哪些参数和对象属性。每个元素的 XML 示例也将非常有帮助。 最佳答
最近,我一直在阅读有关接口(interface)是抽象的错误概念的文章。一篇这样的帖子是http://blog.ploeh.dk/2010/12/02/InterfacesAreNotAbstract
如果我有一个由第三方实现的现有 IInterface 后代,并且我想添加辅助例程,Delphi 是否提供了任何简单的方法来实现此目的,而无需手动重定向每个接口(interface)方法?也就是说,给定
我正在尝试将 Article 数组分配给我的 Mongoose 文档,但 Typescript 似乎不喜欢这样,我不知道为什么它显示此警告/错误,表明它不可分配. 我的 Mongoose 模式和接口(
我有两个接口(interface): public interface IController { void doSomething(IEntity thing); } public inte
是否可以创建一个扩展 Serializable 接口(interface)的接口(interface)? 如果是,那么扩展接口(interface)的行为是否会像 Serilizable 接口(int
我试图在两个存储之间创建一个中间层,它从存储 A 中获取数据,将其转换为相应类型的存储 B,然后存储它。由于我需要转换大约 50-100 种类型,我希望使用 map[string]func 并根据 s
我正在处理一个要求,其中我收到一个 JSON 对象,其中包含一个日期值作为字符串。我的任务是将 Date 对象存储在数据库中。 这种东西: {"start_date": "2019-05-29", "
我们的方法的目标是为我们现有的 DAO 和模型类引入接口(interface)。模型类由各种类型的资源 ID 标识,资源 ID 不仅仅是随机数,还带有语义和行为。因此,我们必须用对象而不是原始类型来表
Collection 接口(interface)有多个方法。 List 接口(interface)扩展了 Collection 接口(interface)。它声明与 Collection 接口(int
我有一个 Java 服务器应用程序,它使用 Jackson 使用反射 API 对 DTO 进行一般序列化。例如对于这个 DTO 接口(interface): package com.acme.libr
如果我在 Kotlin 中有一个接口(interface): interface KotlinInterface { val id: String } 我可以这样实现: class MyCla
我知道Java中所有访问修饰符之间的区别。然而,有人问了我一个非常有趣的问题,我很难找到答案:Java 中的 private 接口(interface)和 public 接口(interface)有什
我是一名优秀的程序员,十分优秀!