- 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/
话说,尾部的++在这里没有实际作用? 最佳答案 l+l++ 未定义。您的表达式中没有序列点来分隔对 l 的访问和后增量。它可以做任何事情,包括具有与 l+l 相同的效果。 编辑:问题和答案在 Why
我正在研究成员资格算法,我正在研究这个特定问题,该问题说明如下: 展示一种算法,给定任何常规语言 L,确定 L 是否 = L* 所以,我的第一个想法是,我们有 L*,它是 L 的 Kleene 星并确
我试图弄清楚如何使用 Javascript 生成一个随机 11 个字符串,该字符串需要特定的字母/数字序列,以及位置。 ----------------------------------------
我一直在 LinqPad 中试验查询。我们有一个表 Lot,其中有一列 Side char(1)。当我编写 linq to sql 查询 Lots.Where(l => l.Side == 'A')
这个问题在这里已经有了答案: Iterate over all pairs of consecutive items in a list [duplicate] (7 个答案) 关闭 7 年前。 假
列表 ['a','a #2','a(Old)'] 应变为 {'a'} 因为 '# ' 和 '(Old)' 将被删除,并且不需要重复项列表。我努力用生成器开发列表理解,并决定这样做,因为我知道它会起作用
我正在为蛇和梯子制作一 block 板,到目前为止,我已经按降序打印了板。但是,我需要以正确的方式打印电路板。 编辑“螺旋下降”意味着 100...91 81...90 80...71 ...
字符串“Hello\n”等于 {'H','e','l','l','o','\','n','\0'} 或 {'H','e','l','l','o','\n','\0'}? 是否在字符串定义中添加转义序列
这个问题在这里已经有了答案: Different behaviour for list.__iadd__ and list.__add__ (3 个答案) 关闭 8 年前。 ls = [1,2,3]
当我在编写一个程序时,我在我的代码中看到了一个奇怪的行为。这是我所看到的。 >>> l = [1,2,3,4,5,6,7,8] >>> g = [] >>> for i in l: ... g
我明白了what a Y Combinator is , 但我不明白这个来自 Wikipedia page 的“新颖”组合子的例子: Yk = (L L L L L L L L L L L L L
Exception ParseException is not compatible with throws clause in Comparator.compare(L, L). 我在java 6上
期望的输出 我想要一个函数返回一个列表,这样,给定一个“困惑的”列表 l,每个元素都是 l 对应元素的索引,如果 l 已排序。 (抱歉,我想不出更简单的说法。) 示例 f([3,1,2]) = [2,
你好,我正在查看“假设一个排序数组在你事先不知道的某个枢轴旋转。(即 0 1 2 4 5 6 7 可能变成 4 5 6 7 0 1 2)”这个问题的 C++ 解决方案。你如何有效地在旋转数组中找到一个
让我们考虑这个简单的例子: import numpy as np a=np.arange(90) a=a.reshape(6,3,5) 我想得到一个数组 b形状 (6*5,3+1=4) 与 b[0:6
我正在编写一个 q 脚本,它在特定路径中加载一个数据库并对其进行一些处理。 db 的位置目前在脚本中是硬编码的,但我想将 db 路径作为参数传递并让它从变量中的路径加载。 目前它看起来像这样: q)
为什么我收到错误 Device: (3:9741) (0,l.useLinkBuilder) is not a function。 (在 '(0,l.useLinkBuilder)()' 中,'(0,
我有 ADT 版本 23.0.4 并安装了 Android 5.0 的 SDK 平台。 我读到 Android 5.0 Lolipop 的 API 级别为 21。但是在 Eclipse 的“新建应用程
我在 Google Play Store 中实现了一个抽屉导航,我想在 DrawerLayout 中设置列 TableView 的选定项目。但是后来发现在touch模式下无法选中item,有一个i
作为 C++ 的新手,我基本上有一个关于 g++ 编译器的问题,尤其是库的包含。考虑以下生成文件: CPPFLAGS= -I libraries/boost_1_43_0-bin/include/ -
我是一名优秀的程序员,十分优秀!