来深圳已一月有余,回望这段时间,收获颇多呀。 两周学习can通信协议,并且驱动电机,这个就不细说了。这次主要说一下刚完成的温度控制模块的项目,因为在此项目中实在收获不少呀。 这最开始,要说一下程序代码的结构策划,这是本次项目中最大的收获。这个技能可以说给我的代码生涯打开了一个新的大门。主要通过两个方面着手如何学习代码的结构策划:一个是公司前辈的指点,另一个就是《程序员的思维修炼》这本书给到的思维上的启迪。下面就以温控系统为例,来简单说一下。 以框架来写代码,首先要做一个构思:从最顶层的功能开始写起,然后一步一步拆分,一直到最底层。如下: 具体到温控模块 当完成了整个功能模块的构划,接下来写代码就要从最底层开始写起,驱动层,数据处理层,应用层,这样一层一层往上实现。当学会先搭框架,再去写程序,思路会更清晰,后续阅读代码和移植代码也会很方便。 另外多说一下在其中用到的一个减小温度稳定范围的技巧(其实用pid算法更好,但时间紧迫,后续会补一个pid算法稳定温度的博客),这里就先只是说一下我所想到的一个方法。主要分成两个部分,一部分是adc值得滤波,得到更可靠的值。操作步骤是先冒泡排序,在去头去尾。代码如下:
//冒泡排序 //输入参数:*dat:排序的数据 len:排序的数据长度 //输出参数:无 void Temp_Sort(uint16_t *dat, int len) { uint16_t t; u8 i; u8 j; for( i=0;i<len-1;i++) { for( j=0;j<len-1-i;j++) { if(dat[j]>dat[j+1]) { t=dat[j]; dat[j]=dat[j+1]; dat[j+1]=t; } } } } //adc数据滤波 //输入参数:ch:adc对应通道值 len:数据长度 //输出参数:temp_val/10:滤波后的值 uint16_t Temp_Get_ADC_Average1(u8 ch, int len) { u32 temp_val=0; uint16_t a[SIZE]; u8 n; for(n = 0; n < SIZE; n++) {//ch是因为用到了多个adc通道测试 a[n] = adcvalue[n][ch]; //将adc数据存入数组中 } Temp_Sort(a, len); for(n=20;n<30;n++) //去头去尾留中间十个 { temp_val+=a[n]; } return temp_val/10; }第二部分是加热片的一个开断处理,思路是模仿pwm的电平输出,设定以十秒为一个周期,改变参数来调整占空比。具体实现方法:设定定时器为一秒进入一次中断,进入中断后参数a加一,十次后归零,参数a通过与调整占空比的参数做比较来判断是否打开加热片。代码如下:
u8 time_mun = 0; #define time_end 10; //定时器3中断服务程序 void TIM3_IRQHandler(void) //TIM3中断 { if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否 { TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中断标志 time_mun++; if(time_mun >= time_line1) { T1 = ON; } if(time_mun == time_end) { time_mun = 0; T1 = OFF; } } }此外,在温度比较这里也做了一个处理,具体用代码体现:
//将温度稳定在一个目标值 u8 time_line1 = 0; u8 Func_Constant_Temperature(float state, float target) { u8 flag = 10; if(state == 0) return 0; if(state < target - 1) //温度小于目标值 { time_line1 = 0; } else if(state >= target + 1) //温度大于目标值 { time_line1 = 10; } else { if(flag == 0) { time_line1 = 5; } else if(flag == 1) { } else { } } return 0; }