首页 > 代码库 > 明确目的以及不要过早优化

明确目的以及不要过早优化

  上周的嵌入式实验课做了一个关于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不是白给的。