单片机实用编程技巧值得学习

上传人:ldj****22 文档编号:51202609 上传时间:2018-08-12 格式:PPT 页数:31 大小:68KB
返回 下载 相关 举报
单片机实用编程技巧值得学习_第1页
第1页 / 共31页
单片机实用编程技巧值得学习_第2页
第2页 / 共31页
单片机实用编程技巧值得学习_第3页
第3页 / 共31页
单片机实用编程技巧值得学习_第4页
第4页 / 共31页
单片机实用编程技巧值得学习_第5页
第5页 / 共31页
点击查看更多>>
资源描述

《单片机实用编程技巧值得学习》由会员分享,可在线阅读,更多相关《单片机实用编程技巧值得学习(31页珍藏版)》请在金锄头文库上搜索。

1、单片机软件系统 设计教程基础要求 熟练运用C语言编程。 熟练掌握和运用一款单片机。包括硬件 结构、寄存器、外设、了解基本汇编指 令等。 熟悉一款集成开发环境及编译器。 独立编写并调通2000行以上的小型程序 。一、如何编写高质量软件 合理划分函数功能,合并常用函数 严格的函数、变量命名方法 合理划分软件层次。如硬件隔离层、驱 动程序层、功能函数层、应用层。 合理运用宏定义,提高程序可移植性 经常查看反汇编代码,练习优化指令。函数划分 常用的功能集合,可以合理合并成一个函 数 利用参数传递,将多个函数合并。 例如:某菜单需要将选中的菜单条反色显示,因此需要2 个中文显示函数: DisplaySt

2、ring(char *ptr,char x,char y); DisplayStringInvert(char *ptr,char x,char y); 可以合并成一个函数 DisplayString (char *ptr,char x,char y,bool InvertFlag); 注意函数过分合并会造成运算性能下降。函数与变量命名 严格按照 模块名_功能名 的方法命名,按 正确的英文(甚至拼音也可)命名 单词首字母大写 例如:ADC_CailbrateZero() CPU_SleepDelay(int Time_ms) Flash_WriteWord(int Addr,int Word)

3、软件层次划分 合理划分软件层次,将使程序结构清晰 层次良好的软件,移植性强 对软件开发者来说,便于管理和维护, 甚至可实现“代码免维护” 大大提高开发速度。 例:在某液晶上需要做中文菜单、数字 显示、波形显示、滚动条等。为该应用 编写液晶驱动函数。LCD驱动层划分范例 每一层含义明确, 功能完整独立 每一层只调用其下 一层的函数,禁止跨 层调用函数。 所有变量对于非其 它层函数不透明。 禁止跨层使用全局 变量 层次划分越多,执 行效率越低 更改或更换任何一 层的函数,不影响 其它层函数的执行 。合理运用宏定义 1.用宏定义作硬件隔离#define LED1_POUT P1OUT#define

4、LED1_PDIR P1DIR#define LED1_BIT (BIT2) /*更换IO只需改以上3行 */ #define LED_ON LED1_POUT |= LED1_BIT /*亮*/#define LED_OFF LED1_POUT UBR10 = 0x00; .#define TIMER_PERIOD 12000.TH1=(unsigned int)(65536-TIMER_PERIOD)/256;/*51单片机 */TL1=(unsigned int)(65536-TIMER_PERIOD)%256;. 用宏定义作编译开关#define AVE 0 #define RMS 1

5、 #define PEK 2 #define UMODE AVE /AVE:平均值 RMS真有效值 PEK 峰值*/ . #if (UMODE=RMS) VAC_Ch1=(long int)TempIntV1*TempIntV1;VAC_Ch2=(long int)TempIntV2*TempIntV2; #endif #if (UMODE=AVE)VAC_Ch1=absv(TempIntV1);VAC_Ch2=absv(TempIntV2); #endif .用宏定义作功能开关 #define ON 1 #define OFF 0 #define HI_LO 2 #define LEV_2

6、1 #define NONE 0 #define MINORCUT OFF /*是否打开小值切除功能*/ #define RS485 ON /*是否打开RS-485通讯功能 */ #define DAC ON /*是否打开变送功能*/ #define DEFAULT OFF /*是否打开参数备份功能*/ #define ALARM_MODE NONE/*报警模式 NONE=无报 警 LEV_2=双限 HI_LO=高低限 */ #define OFFSET ON/*是否打开偏移补偿功能*/ #define KEYTONE ON/*按键音*/程序优化 打开编译器自带的优化选项。注意高级 别优化会删

7、除部分“冗余”代码,或改动 程序结构,应注意挥发性变量(volatile ) 查看反汇编代码,看汇编代码是否有冗 余操作,合理修改。二、软件结构 如何让CPU尽可能多地执行多项任务 如何让CPU尽可能快地响应各个事件 如何让程序尽可能少地占用RAM 如何让程序具有尽可能强的可扩展性 如何让编出的程序尽可能通用 如何减少编程工作量?如何减少错误概 率和调试工作量? 好的程序结构,可以解决上述问题实时性 实时性最高的任务,需要零延迟立即响 应。应考虑硬件实现。如用 CPLD/FPGA、捕获等实现。 实时性较高任务,允许微秒级延迟的事 件,可用中断实现。但背景程序中不允 许长时间关闭中断。且中断处理

8、时间不 宜过长。 实时性较低事件,可以查询。事件查询 1.事件出现时间较长,允许响应延迟也 较长。如某个按键,可以在主循环内直 接查询 2.事件出现时间较短,小于主循环时间 ,但允许响应延迟,可以中断置标志位 ,主程序处理,完毕后清除标志。比如 串口数据桢判别。 3.情况2中,若事件无法产生中断,可 以定时中断查询,置标志位。主程序处 理顺序多任务程序 void main (void) int counter = 0; while (1) /* repeat forever */SleepDelay_ms(10);check_serial_io (); /* check for serial

9、input */process_serial_cmds (); /* process serial input */check_kbd_io (); /* check for keyboard input */process_kbd_cmds (); /* process keyboard input */adjust_ctrlr_parms (); /* adjust the controller */counter+; /* increment counter */if(counter%100=0) 并发多任务程序void main() while(1) LPM0; 串口中断 键盘中断 定

10、时中断 休眠事件 B事件 C事件 A事件 D低功耗程序首选结构 每个事件不宜执行时间过长 注意中断随机嵌套,注意保护临界代码全部信息通过全局变量传递和保存前后台程序Void main() while(1)等待1秒延迟读取电压计算温度显示温度报警处理 定时中断串口中断最常见的程序结构背景程序与前台程序之间通过 全局变量传递注意中断用到全局变量的保护注意临界代码的保护主程序不能长时间关闭中断中断程序尽量简短,尽快返回 。注意避免函数递归调用RTOS 嵌入一个微型实时操作系统(RTOS), 可以轻松实现多任务(进程)并发执行 。 商品化或免费的的RTOS,如uC-OSII, RTX-TINY,国产S

11、mall-RTOS等。 允许每个任务都是死循环,由RTOS负 责调度CPU程序指针分时执行每个任务 。 CPU、RAM开销较大,8位CPU或简单 程序不建议使用。避免函数重入 重入(reentrant):指函数直接或间接调 用函数自身。 和PC不同,PC采用堆栈传递允许函数 重入。单片机采用静态变量传递,不允 许函数重入。 造成重入的原因: 1.递归调用。例如A函数调用B函数,B函 数调用C函数,C函数调用A函数。 避免函数重入 2.中断重入假设主程序循环会调用A函数,中断也 使用了A函数,那么有可能在主循环A 函数执行一半的时候,中断,又执行A 函数,造成A函数原来的变量被更改。 3.硬件重

12、入假设主程序操作液晶显示,中断也操作 液晶显示,有可能在液晶时序一半的时 候,中断,时序重新开始,造成液晶收 到错误指令,发生不可恢复的错误。临界代码保护 临界代码(Critical Code):指运行过程 中不允许被中断打断的代码。 几种产生临界代码的原因: 1.执行时间严格,不允许被延长。如软件 模拟串口,软件循环产生精确延迟,软 件模拟时间严格的异步时序(如1Wire 总线),不允许被打断。临界代码保护 2.中断时间很长,某函数不允许长时间 暂停。比如液晶。 3.因为避免函数重入产生的临界代码。 再写一个一样的函数,专供中断用。 用reentrant关键字定义函数(堆栈传递 参数) 进入

13、临界代码前关中断,后开中断。临界代码保护 2. 中断变量传递造成的临界代码: 例如,主程序要得到存有周期计数值的长整形变量 PeriodCnt。该 值在中断内被更新。 中断: PeriodCnt= TAOF_Cnt*65536+TAR; Main Freq= 1.0/PeriodCnt;/错误! _DINT(); TempL=PeriodCnt;_EINT();Freq= 1.0/ TempL; /正确! 对象化编程 单片机系统的任何一个独立单元/部件/ 外设/功能集合,都可以抽象成一个对 象(Object)。 对象都有其 属性、方法、事件。 以IO为例。 属性:方向、电平。 方法:置1,置0

14、,取反,读取输入值,读 取方向 事件:跳变,中断对象化编程 IO1_DIR IO1_IN 作为其属性,可以被 设置。 方法 IO1_Set(Bool), IO1_Neg(); 事件 IO1_Interrupt();基于状态机编程 例:当某对象处于A状态时,假设发生 了B事件,就执行C代码,并且跳转到D 状态。 例:电子表。键A 键B 1.当显示时间时(状态1),按下键A,就 显示日期。 2.当显示日期时,按下A键,就显示秒 3.当显示秒时,按下A键,回到显示时间 。例:电子表 4.当显示时间时,按下B键,时闪烁,提 示设置“时” 5.当提示提示设置“时”,按B键,分闪烁 6.当分闪烁时按B键,月闪烁 7.当月闪烁时按B键,日闪烁 8.当日闪烁时按B键,恢复时间显示 9.时闪烁时,按A键,时+1,若超过12归0 10.分闪烁时,按A键,分+1,若超过59归 0例:电子表 11.月闪烁时,按A键,月+1,若超过12归0 12.日闪烁时,按A键,日+1,若超过31归0 13.显示秒时,按B键,秒归0状态跳转图正常显示日期显示 A秒显示AA设置时设置分设置月设置日BBBBB秒=0B分+A月+A日+A时+A系统抽象 属性可以为7种值 方法有5种 事件有2种

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号