上周的嵌入式实验课做了一个关于ADC的实验,即用从5V中用变阻器分出一部分电压,用ADC采样量化作为输入信号,要求是使LED闪烁频率随这个信号限值(包括上限A上和下限A下)的幅度的增大而变快。
设输入信号幅度是A,一个思路是用延时,A-A下
越大,两次亮灯之间的延时越小,这样也就是闪得越快了。低于下限的时候同理。不过这篇随笔主要不是讲这个思路有多好(一般都能想到这个思路),而是要说它的实现。
先说说当时是怎么做的吧。。由于已经给了例程,一般情况下为了图方便省事是直接修改,或者调用里面的函数(而且是只看接口不看内部)。一般情况下都有这么一个Delay的函数
<main.c>中
extern __IO uint32_t TimingDelay;
void Delay(__IO uint32_t nTime)
{
TimingDelay = nTime;while(TimingDelay != 0);
}
在写中断源文件<stm32f10x_it.c>中
__IO uint32_t TimingDelay = 0;
void SysTick_Handler(void)
{
TimingDelay--;
}
当然还要配置SysTick,打开定时器,这样才能进入SysTick_Handler中断
可是上面这些都配置好了以后,这个Delay函数只能在main.c 中调用,但问题是 LED亮灭(闪烁)本身就是在中断里面完成的
void ADC1_2_IRQHandler(void)
{
/* Toggle LED1 */
STM_EVAL_LEDOn(LED1);
printf("interrupt occur\r");
STM_EVAL_LEDOff(LED1);
printf(" \r");
/* Clear ADC1 AWD pending interrupt bit */
ADC_ClearITPendingBit(ADC1, ADC_IT_AWD);
}
如果在stm32f10x_it.c中调用Delay,即
void ADC1_2_IRQHandler(void)
{
/* Toggle LED1 */
STM_EVAL_LEDOn(LED1);
Delay(500);
printf("interrupt occur\r");
STM_EVAL_LEDOff(LED1);
Delay(500);
printf(" \r");
/* Clear ADC1 AWD pending interrupt bit */
ADC_ClearITPendingBit(ADC1, ADC_IT_AWD);
}
显示结果就是灯一直亮,也就是说进入
Delay(包括SysTick)以后就出不来了。。再转电位器也无济于事。这其中可能有很多原因,比如中断嵌套,优先级,标志位或者什么地方没有设置好,反正就是得不到想要的结果。由于机房的环境以及时间捉急(还有没法上网百度谷歌),越搞越搞不出来。
(下面才是本文重点要说的)
这时候朱哥提醒了我,要不用for循环来做延时得了。一试如梦初醒茅塞顿开!然后一下子有了很多想法(主要是反思)思维又被限制了好吗!
来整理一下:
1.
//说明:ADC给过来的值的范围A是0~4096,A上是2816,A下是768
// 系统晶振是25M
// 3000是放大因子
void ADC1_2_IRQHandler(void)
{
/* Toggle LED1 */
int i=0;STM_EVAL_LEDOn(LED1);
if(ADC_GetConversionValue(ADC1)>2000){
for(i=ADC_GetConversionValue(ADC1)*3000;i<12500000;i++);
}else{
for(i=(2000-ADC_GetConversionValue(ADC1))*6000;i<12500000;i++);
}
printf("interrupt occur\r");STM_EVAL_LEDOff(LED1);
if(ADC_GetConversionValue(ADC1)>2000){
for(i=ADC_GetConversionValue(ADC1)*3000;i<12500000;i++);
}else{
for(i=(2000-ADC_GetConversionValue(ADC1))*6000;i<12500000;i++);
}
printf(" \r");/* Clear ADC1 AWD pending interrupt bit */
ADC_ClearITPendingBit(ADC1, ADC_IT_AWD);
}
试验效果OK,达到要求。
2.
刚学51的时候,郭天祥老师的书上教了两种延时的方法:可以直接在其中用for循环来耗掉时间,这种方法中间不能做其他事,而且不是很精确;
//<新概念51单片机C语言教程>中用来延时n毫秒的方法
//当然也可以只用一个for
void delay_ms(uint n)
{
uint x,y;
for(x=0;x<n;x++)
for(y=0;y<120;y++);
}
也可以用中断来实现,这样可以在期间做其他事情,既保证了效率又可以更精确计时。
但是,并非所有场合都必须要用中断!在要求不高(时间精度或者功耗要求等)的场合,for延时够用了!简单方便,测试看延时的效果够用了。
要把学过的东西融汇贯通,思维不要被约束和限制,明确目的!这里的目的首先是要达到要求,其次才是看你会不会正确用中断什么的
3.
3.1
《黑客与画家》的译者总结,原著作者Paul Graham有一套完整的创业哲学,他的创业公式是:
(1)搭建原型
(2)上线运营(别管bug)
(3)收集反馈
(4)调整产品
(5)成长壮大
Paul
Graham还指出,不要过早优化你的产品,在这次实验中也有异曲同工之妙。先完成作业要求,而不要一开始就想着出一个完美的作品,然后再进一步优化,至少在完成要求后心态更好,头脑清晰,不会有焦虑之急,有利于优化工作的进行。
3.2
看上去更近的路不一定是捷径(比如直接从另一个工程里面把与Delay函数有关的的抄过来,在这里就是用不了),绕远路可能更快,这样的例子在生活中很常见。
至少需要先思考一下再行动,大脑这个智能CPU不是白给的。
明确目的以及不要过早优化