吴坚鸿风格的C51程序-1
c51程序设计基础doc - 第一讲 建立您的第一个C项目-推荐下载
C51 程序设计基础
3
C51 程序设计基础
出菜单,在这里可以做在项目中增加减少文件等操作。我们?quot;Add File to Group 'Source Group 1'"弹出文件窗口,选择刚刚保存的文件,按 ADD 按钮,关闭文件窗,程序文件已加到项目中了。这时在 Source Group1 文件夹图标左边出现了一个小+号说明,文件组中有了文件,点击 它可以展开查看。
怀化职业技术学院电子电气工程系——自动化教研室 11/28/2006
对全部高中资料试卷电气设备,在安装过程中以及安装结束后进行高中资料试卷调整试验;通电检查所有设备高中资料电试力卷保相护互装作置用调与试相技互术通关,1系电过,力管根保线据护敷生高设产中技工资术艺料0不高试仅中卷可资配以料置解试技决卷术吊要是顶求指层,机配对组置电在不气进规设行范备继高进电中行保资空护料载高试与中卷带资问负料题荷试2下卷2,高总而中体且资配可料置保试时障卷,各调需类控要管试在路验最习;大题对限到设度位备内。进来在行确管调保路整机敷使组设其高过在中程正资1常料中工试,况卷要下安加与全强过,看度并22工且22作尽22下可22都能22可地护以缩1关正小于常故管工障路作高高;中中对资资于料料继试试电卷卷保破连护坏接进范管行围口整,处核或理对者高定对中值某资,些料审异试核常卷与高弯校中扁对资度图料固纸试定,卷盒编工位写况置复进.杂行保设自护备动层与处防装理腐置,跨高尤接中其地资要线料避弯试免曲卷错半调误径试高标方中高案资等,料,编试要5写、卷求重电保技要气护术设设装交备备置底4高调、动。中试电作管资高气,线料中课并敷3试资件且、设卷料中拒管技试试调绝路术验卷试动敷中方技作设包案术,技含以来术线及避槽系免、统不管启必架动要等方高多案中项;资方对料式整试,套卷为启突解动然决过停高程机中中。语高因文中此电资,气料电课试力件卷高中电中管气资壁设料薄备试、进卷接行保口调护不试装严工置等作调问并试题且技,进术合行,理过要利关求用运电管行力线高保敷中护设资装技料置术试做。卷到线技准缆术确敷指灵设导活原。。则对对:于于在调差分试动线过保盒程护处中装,高置当中高不资中同料资电试料压卷试回技卷路术调交问试叉题技时,术,作是应为指采调发用试电金人机属员一隔,变板需压进要器行在组隔事在开前发处掌生理握内;图部同纸故一资障线料时槽、,内设需,备要强制进电造行回厂外路家部须出电同具源时高高切中中断资资习料料题试试电卷卷源试切,验除线报从缆告而敷与采设相用完关高毕技中,术资要资料进料试行,卷检并主查且要和了保检解护测现装处场置理设。备高中资料试卷布置情况与有关高中资料试卷电气系统接线等情况,然后根据规范与规程规定,制定设备调试高中资料试卷方案。
[PIC单片机] 吴坚鸿单片机程序风格赏析【1】
(一)按键行列扫描与蜂鸣器(1)技术体会:在行列式扫描结构的薄膜按键里,干扰很大,按键扫描程序非常讲究,尤其是去抖动的处理。
(2)功能需求:每按一个按键,蜂鸣器就响一次。
(3)硬件原理:(a)用4个IO来做2X2按键行列扫描,其中作为输入的2个IO口必须接上拉电阻20K左右。
(b)用1个IO经过8050三极管来驱动有源蜂鸣器,有源蜂鸣器通电就一直响,断电就停止。
而无源蜂鸣器是要靠断断续续的开关信号来驱动才能响,就是要频率来驱动。
(4)源码适合的单片机:PIC18F4620,晶振为22.1184MHz(5)源代码讲解如下:#include<pic18.h> //包含芯片相关头文件//补充说明:吴坚鸿程序风格是这样的,凡是输出IO后缀都是_dr,凡是输入的//IO后缀都//是_sr#define beep_dr LATA1 //蜂鸣器输出#define key_dr1 LATB3 //2X2按键行输出#define key_dr2 LATB4 //2X2按键行输出#define key_sr1 RB6 //2X2按键行输入#define key_sr2 RB7 //2X2按键行输入//补充说明:吴坚鸿程序风格是这样的,凡是做延时计数阀值的常量//前缀都用cnt_表示。
#define cnt_delay_cnt1 25 //按键去抖动延时阀值#define cnt_delay_cnt2 5 //按键行输出信号稳定的小延时阀值#define cnt_voice_time 60 //蜂鸣器响的声音长短的延时阀值void delay1(unsigned int de) ;//小延时程序,时间不宜太长,因为内部没有喂看门狗//补充说明:吴坚鸿程序风格是这样的,凡是按键扫描函数都放在定时中//断里,凡是按键服务程序都是放在main函数循环里。
有人说不应该把子程序//放在中断里,别听他们,信鸿哥无坎坷。
基于C51单片机擂台机器人的设计
2.4 模数转化芯片 ADC0809
ADDA、ADDB、ADDC:3 位地址输入线,用于 选通 8 路模拟输入中的一路。
ALE:地址锁存允许信号,输入,高电平有效。 START:A/D 转换启动信号,输入,高电平有 效。 EOC:A/D 转换结束信号,输出,当 A/D 转 换结束时,此端输出一个高电平(转换期间一直为低 电平)。 OE:数据输出允许信号,输入,高电平有效。当 A/D 转换结束时,此端输入一个高电平,才能打开 输出三态门,输出数字量。 CLK:时钟脉冲输入端。要求时钟频率不高于 640KHZ。
238
4 红外隐身外壳设计
5 结束语
本文设计的是基于 c51 单片机的擂台 基 机器人,趣味性强,能提升大学生的创新设 于
C51
计能力、综合设计能力和团队合作精神,培
养大学生根据实际需求进行创新思维、机械
单 片
设计和工艺制作等实际工作能力,并以此为
机 擂
契机促进大学生课外科技创新活动的蓬勃
台 机
开展。
是 SGS 公司的产品,内部包含 4 通道逻辑驱动电 路。是一种二相和四相电机的专用驱动器,即内含 二个 H 桥的高电压大电流双全桥式驱动器,接收标 准 TTL 逻辑电平信号,可驱动 46V、2A 以下的电 机。
要注意的是,L298N 驱动的 5V 端口可以直接 对单片机供电。
模块接口说明: +5V:芯片电压 5V。 VCC:电机电压,最大可接 50V。 GND:共地接法。 A-~D-:输出端,接电机。 A~D+ : 为 步 进 电 机 公 共 端 , 模 块 上 接 了 VCC。 EN1、EN2:高电平有效,EN1、EN2 分别为 IN1 和 IN2、IN3 和 IN4 的使能端。 IN1~ IN4:输入端,输入端电平和输出端电平是 对应的。 3 软件设计 系统整体流程图如图七所示。
[PIC单片机] 吴坚鸿单片机程序风格赏析【9】
第五十五节:按键的花样技巧----双击按键的触发开场白:从这一节开始,我准备花几个章节来讲讲按键的几种常用花样技巧。
(1)功能需求:在规定的时间内,连续按两次按键则触发蜂鸣器发出“嘀”的短暂按键声。
类似于电脑鼠标的双击按键。
(2)硬件原理:独立按键和有源蜂鸣器的硬件原理请参考本连载文章的第二节。
(3)源码适合的单片机: PIC16F73,晶振为3.579545MHz。
(4)单片机的C语言源代码讲解:#include<pic.h>#define const_delay 1000 //连续按两次有效按键触发的时间单位。
当然此数据的大小我没仔细验证过,读者根据实际情况来调整.#define cnt_delay_cnt1 25 //按键去抖动延时阀值#define cnt_voice_time 60 //蜂鸣器响的声音长短的延时阀值//补充说明:吴坚鸿程序风格是这样的,凡是输出IO后缀都是_dr,凡是输入的IO后缀都是_sr#define beep_dr RB1 //蜂鸣器输出#define key_sr1 RB6 //独立按键输入启动按键//补充说明:吴坚鸿程序风格是这样的,按键扫描函数通常放在定时中//断里,按键服务程序通常放在main函数循环里。
有人说不应该把子程序放在中断里,别听他们,信鸿哥无坎坷。
void key_scan(); //按键扫描函数,放在定时中断里void key_service(); //按键服务函数,放在main函数循环里unsigned long time_cnt=0; //两次有效按键的时间计数器unsigned char key_lock1=0; //按键自锁标志unsigned int delay_cnt1=0; //按键去抖动的延时计数器的变量unsigned int voice_time_cnt; //蜂鸣器响的声音长短的计数延时unsigned char key_sec=0; //哪个按键被触发unsigned char key_touch_cnt=0; //按键触发的次数统计main() //主程序{ADCON0=0x41; //设置AD模式ADCON1=0x04; //RA0作为AD输入通道,本程序中没有用到AD,不用管它TRISB1=0; //蜂鸣器设置成输出beep_dr=0; //上电初始化蜂鸣器TRISB6=1; //独立按键设置成输入T1CON=0x24; //定时中断配置TMR1H=0xFE;TMR1L=0xEF;INTCON=0xC0;TMR1IF=0;TMR1IE=1;PEIE=1; //外围中断允许GIE=1; //开总中断TMR1ON=1; //启动定时器中断while(1){CLRWDT(); //喂单片机内部自带的看门狗,大家可以不管它key_service(); //按键服务}}void key_scan() //按键扫描函数{if(key_sr1==1) //IO是高电平,说明按键没有被按下,这时要及时清零一些标志位{key_lock1=0; //按键自锁标志清零delay_cnt1=0; //按键去抖动延时计数器清零,此行非常巧妙,仔细品味,回味无穷,在按键去抖动期间,如果低电平掺杂了干扰的高电平,则计数器重新清零计数,极大增强了抗干扰的能力。
吴鸿坚--串口程序
#in elude "REG52.H"#defi ne con st_se nd_size #defi ne con st_key_time1#defi ne con st_voice_short 40〃蜂鸣器短叫的持续时间void in itial_myself(void);void in itial_ perip heral(void);void delay_short (un sig ned int uiDelayshort);void delay_ long(un sig ned int uiDelay Ion g);void eusart_se nd(u nsig ned char ucSe ndData); //发送一个字节,内部自带每个字节之间的延时 void TO_time(void); // 定时中断函数 void usart_receive(void); // 串口接收中断函数void key_service(); //按键服务的应用程序void key_sca n(); //按键扫描函数 放在定时中断里sbit led_dr=卩1人5; //Led 的驱动 IO 口sbit beep_dr=卩2人5; //蜂鸣器的驱动IO 口sbit key_sr1=卩3人2; //对应朱兆祺学习板的 S1键 sbit key_gnd_dr= POM; //模拟独立按键的地 GND ,因此必须一直输出低电平 unsigned charucSendregBuf[const_send_size]; // 接收串口中断数据的缓冲区数组un sig ned int uiVoiceC nt=O;//蜂鸣器鸣叫的持续时间计数器 un sig ned char ucVoiceLock=0; 〃蜂鸣器鸣叫的原子锁un sig ned char ucKeySec=0;// 被触发的按键编号 unsigned int uiKeyTimeCnt1=O; //按键去抖动延时计数器 unsigned char ucKeyLock1=0; //按键触发后自锁的变量标志 void mai n(){in itial_myself();delay_lo ng(100);in itial_ perip heral();while(1){key_service(); II 按键服务的应用程序} void eusart_se nd(un sig ned char ucSe ndData) {10 //串口发送数据的缓冲区数组大小20 〃按键去抖动延时的时间ES = 0; //关串口中断TI = 0; II 清零串口发送完成中断请求标志SBUF =ucSendData; II 发送一个字节I*注释一:*根据我个人的经验, 在发送一串数据中,每个字节之间必须添加一个延时, 用来等待串 口发送完成。
---C51例程
初学者必备第01 篇基础程序设计01 闪烁的LED/* 名称:闪烁的LED说明:LED按设定的时间间隔闪烁*/#include<reg51.h>#define uchar unsigned char#define uint unsigned intsbit LED=P1^0;//延时void DelayMS(uint x){uchar i;while(x--){for(i=0;i<120;i++);}}//主程序void main(){while(1){LED=~LED;DelayMS(150);}}02 从左到右的流水灯/* 名称:从左到右的流水灯说明:接在P0口的8个LED从左到右循环依次点亮,产生走马灯效果*/#include<reg51.h>#include<intrins.h>#define uchar unsigned char#define uint unsigned int//延时void DelayMS(uint x){uchar i;while(x--){for(i=0;i<120;i++);}}//主程序void main(){P0=0xfe;while(1){P0=_crol_(P0,1); //P0的值向左循环移动DelayMS(150);}}03 8只LED左右来回点亮/* 名称:8只LED左右来回点亮说明:程序利用循环移位函数_crol_和_cror_形成来回滚动的效果*/#include<reg51.h>#include<intrins.h>#define uchar unsigned char#define uint unsigned int//延时void DelayMS(uint x){uchar i;while(x--){for(i=0;i<120;i++);}}//主程序void main(){uchar i;P2=0x01;while(1){for(i=0;i<7;i++){P2=_crol_(P2,1); //P2的值向左循环移动DelayMS(150);}for(i=0;i<7;i++){P2=_cror_(P2,1); //P2的值向右循环移动DelayMS(150);}}}04 花样流水灯/* 名称:花样流水灯说明:16只LED分两组按预设的多种花样变换显示*/#include<reg51.h>#define uchar unsigned char#define uint unsigned intuchar code Pattern_P0[]={0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe7,0xdb,0xbd,0x7e,0xbd,0xdb,0xe7,0xff,0xe7,0xc3,0x81,0x00,0x81,0xc3,0xe7,0xff, 0xaa,0x55,0x18,0xff,0xf0,0x0f,0x00,0xff,0xf8,0xf1,0xe3,0xc7,0x8f,0x1f,0x3f,0x7f,0x7f,0x3f,0x1f,0x8f,0xc7,0xe3,0xf1,0xf8,0xff,0x00,0x00,0xff,0xff,0x0f,0xf0,0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe,0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe, 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff};uchar code Pattern_P2[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f,0xff,0xe7,0xdb,0xbd,0x7e,0xbd,0xdb,0xe7,0xff,0xe7,0xc3,0x81,0x00,0x81,0xc3,0xe7,0xff, 0xaa,0x55,0x18,0xff,0xf0,0x0f,0x00,0xff,0xf8,0xf1,0xe3,0xc7,0x8f,0x1f,0x3f,0x7f,0x7f,0x3f,0x1f,0x8f,0xc7,0xe3,0xf1,0xf8,0xff,0x00,0x00,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff};//延时void DelayMS(uint x){uchar i;while(x--){for(i=0;i<120;i++);}}//主程序void main(){uchar i;while(1){ //从数组中读取数据送至P0和P2口显示for(i=0;i<136;i++){P0=Pattern_P0[i];P2=Pattern_P2[i];DelayMS(100);}}}05 LED模拟交通灯/* 名称:LED模拟交通灯说明:东西向绿灯亮若干秒,黄灯闪烁5次后红灯亮,红灯亮后,南北向由红灯变为绿灯,若干秒后南北向黄灯闪烁5此后变红灯,东西向变绿灯,如此重复。
C51经典程序
经典程序1.广告灯的左移右移1.实验任务做单一灯的左移右移,硬件电路如图4.4.1所示,八个发光二极管L1-L8分别接在单片机的P1.0-P1.7接口上,输出“0”时,发光二极管亮,开始时P1.0→P1.1→P1.2→P1.3→┅→P1.7→P1.6→┅→P1.0亮,重复循环。
2.电路原理图图4.4.13.系统板上硬件连线把“单片机系统”区域中的P1.0-P1.7用8芯排线连接到“八路发光二极管指示模块”区域中的L1-L8端口上,要求:P1.0对应着L1,P1.1对应着L2,……,P1.7对应着L8。
4.程序设计内容我们可以运用输出端口指令MOV P1,A或MOV P1,#DATA,只要给累加器值或常数值,然后执行上述的指令,即可达到输出控制的动作。
每次送出的数据是不同,具体的数据如下表1所示P1.7 P1.6 P1.5 P1.4 P1.3 P1.2 P1.1 P1.0 说明L8 L7 L6 L5 L4 L3 L2 L11 1 1 1 1 1 1 0 L1亮1 1 1 1 1 1 0 1 L2亮1 1 1 1 1 0 1 1 L3亮1 1 1 1 0 1 1 1 L4亮1 1 1 0 1 1 1 1 L5亮1 1 0 1 1 1 1 1 L6亮1 0 1 1 1 1 1 1 L7亮0 1 1 1 1 1 1 1 L8亮表15.程序框图图4.4.26.C语言源程序#include <A T89X51.H>unsigned char i;unsigned char temp;unsigned char a,b;void delay(void)//延时0.1968s{unsigned char m,n,s;for(m=20;m>0;m--)for(n=20;n>0;n--)for(s=248;s>0;s--); 若改为249则为0.1976s}void main(void){while(1){temp=0xfe;P1=temp;delay();for(i=1;i<8;i++){a=temp<<i;b=temp>>(8-i);P1=a|b;delay();}for(i=1;i<8;i++){a=temp>>i;b=temp<<(8-i);P1=a|b;delay();}}}【电设资料】非常精确的C语言延时子程序表用C语言写出来程序非常的简练,它是一种模块化的语言,一种比汇编更高级的语言,但是就是这样一种语言也还是有它不足之处:它的延时很不好控制,我们常常很难知道一段延时程序它的精确延时到底是多少,这和汇编延时程序没法比。
C51程序设计(完整)
第1章C51数据类型与运算1.1C51数据类型C51的数据类型如下所示:C51编译器支持的数据类型、长度和值域如下表1-1所示。
与面向数学运算的计算机相比,51单片机对变量类型或数据类型的选择更具有关键性意义。
如果在程序设计中使用大量而不必要的变量类型,这会导致C编译器调用库函数的数量,以处理大量的变量类型和数据类型。
所以必须特别慎重地进行变量和数据类型的选择。
1.2C51数据存储类型C51编译器还可以通过将变量、常量定义成不同的存储类型(data,bdata,idata,pdata,xdata,code)的方法,将它们定义在不同的存储区中。
存储类型与51单片机实际存储空间的对应关系如表1-2所示。
储区中。
片内RAM是存放临时性传递变量或使用频率较高变量的理想场所。
访问片内数据存储器(data、bdata、idata)比访问片外数据存储器(xdata、pdata)相对快一些,因此可将经常使用的变量置于片内数据存储器,而将规模较大的或不常使用的数据置于片外数据存储器中。
C51存储类型及其大小和值域如表1-3所示。
例如:表1-3 C51存储类型及其大小和值域char data var1; /*字符变量var1被定义为data存储类型,定位在片内RAM中*/bit bdata flags; /*位变量flags被定义为data存储类型,定位在片内RAM中的位寻址区*//*(20H~2FH)*/float idata x,y,z; /*浮点变量x,y,z被定义为idata存储类型,定位在片内RAM中,并只能用间接寻址的方法进行访问*/unsigned int pdata dimension; /*无符号整型变量dimension被定义为pdata存储类型,定位在片外RAM中,并用MOVX @Ri访问*/ unsigned char xdata vector[10][4][4]; /*无符号字符三维数组变量vector[10][4][4]被定义为xdata存储类型,定位在片外RAM中,占据10×4×4=160个字节空间*/如果在变量定义时省略存储类型标志符,编译器会自动默认存储类型。
[PIC单片机] 吴坚鸿单片机程序风格赏析【6】
第三十六节:EPROM篇--利用单片机内部自带EPROM存储数据开场白:这一节最有价值的可能不是我下面写的源代码讲解,而是我现在正在讲的开场白。
单片机内部自带EPROM存储数据,曾经是我去年一个挥之不去的噩梦。
去年我接了一个小项目,本来预计一个月内搞完的,结果因为小小的EPROM害得我阴沟里翻了船,拖了半年才验收通过。
事情是这样的,这个系统是工作在3.3V,利用单片机内部自带EPROM存储数据,我花了三个星期就交付给客户了,客户做了十几套样板在测试,发现数据偶尔会丢失,逼得我不得不想尽各种办法,比如备份数据等多种方法双管齐下,最终花了半年时间才弄好。
至于我是怎么弄好的我也不想多分享,因为这个系统有特殊性,我仅仅也是巧妙地利用它自身的特殊性才解决,这种解决问题的方法没有复制的价值。
不过从此之后我总结出了以下3条个人教训。
(a)凡是在低于5V电压工作的系统中,千万不要用单片机内部自带EPROM,宁可多花几毛钱也要用外挂的EPROM。
否则凶多吉少。
(b)在5V电压工作的系统中,如果要用单片机内部自带EPROM,那么这款单片机必须自带上电延时和掉电复位功能,同时烧录配置位时必须把这两项功能都打开。
因为单片机自带EPROM最容易丢失数据的时刻就是发生在掉电和上电那段“权力真空”的时间里。
(c)不管是工作在5V还是工作在低于5V的系统中,最保险的方法还是尽量选用外挂的EPROM。
因为去年那个项目给我留下了“成年阴影”,宁可错杀一千也不放过一个。
注:上电延时在PIC的烧录配置位是指power up timer掉电复位在PIC的烧录配置位是指brown out reset那个项目是去年年初开始弄,半年后才验收通过。
之后跟那个老总就几乎没什么联系了,到了年底的时候,突然有一天我接到了他的电话,他问我周末有没有空,他说想专门请我去酒楼吃海鲜,就我和他两个人。
我很开心地答应了,因为我想他肯定有什么大项目要跟我合作了。
[PIC单片机] 吴坚鸿单片机程序风格赏析【3】
第二十节:按键操作液晶显示屏菜单的基本程序框架(1)开场白:大部分带液晶显示屏的机器,都要求可以跟按键进行配合以便达到可以设置机器内部参数的目的,菜鸟们可能会觉得很复杂,可是鸿哥觉得那都是小菜一碟,因为鸿哥在做那么多项目中早已经发现了它们的规律,现在提取出来跟大家分享。
大家不要感激我那么晚了还熬夜写技术贴,要感谢就感谢电子发烧友论坛的管理员zhihuizhou,他花了那么多时间帮我把这个帖子整理出一套目录链接来,我今天看到后非常感动,再苦再忙也不能有负于他。
在编写液晶显示程序中,有两个最核心的要素。
它们分别是窗口变量与更新变量。
(a)窗口变量:在编写整个程序中,必须要有一条主线,然后按键等所有操作都围绕着这条主线展开,这样无论程序有多复杂也不会乱。
这条主线就是窗口(变量名为wd_sec),在窗口的主线下,再分出一个局部窗口(变量名为part_sec)。
(b)更新变量:液晶屏是属于静态控制的屏,因为涉及到整屏更新(wd_update)和局部更新(part_X_Y_update)。
把不用经常更新显示的内容放到整屏更新里,把要经常更新显示的内容放到局部更新里。
大家只要仔细阅读本程序,领悟到了这条窗口变量与更新变量的精髓,以后做再复杂的人机对话界面都难不倒你。
(2)功能需求:结合第二节的独立按键与第十一节的12864显示屏驱动程序,要求可以显示两个窗口,每一屏液晶显示窗口可以显示4行8X16字符的内容,每一行显示一个数字,按“上”“下”键时,每一行中的数字可以上下依次负显,相当于光标上下移动,按“加”“减”键时,被选择中的某一行中带负显的数字会依次增加或减小(最大范围是0至99)。
当负显光标停留在第一屏第4行的数字时,如果继续按“下”键,则负显光标会切换到第二屏的第1行数字。
负显光标停留在第二屏的第4行的数字时,继续按“下”键,则又会切换返回到第一屏的第1行数字。
(3)硬件原理:请参考第二节的独立按键与第十一节的12864显示屏的硬件电路。
[PIC单片机] 吴坚鸿单片机程序风格赏析【5】
第三十二节:温度篇--利用热敏电阻来采集温度开场白:热敏电阻的阻值会随着温度的变化而变化,也就是热敏电阻每个阻值都会对应一个温度值,我们只要用单片机的AD功能读取出热敏电阻所分到的电压,即可计算出热敏电阻的阻值,之后再利用厂家提供给我们的“阻值--温度”表,即可查询到当前环境的温度。
这种采集温度的方式价格便宜,经常用在采集常温的项目,误差+-1度左右,采集的温度范围不宜过大,100度左右最佳。
不适合用在超高温的场所。
它的外表跟普通插件电阻没什么两样,只是有一些厂家把它封装在一个密封的不锈钢外壳里作为防水的探头,其实本质上还是热敏电阻。
可以直接用万用表来量它两端的阻值,当温度变化时可以看到它的阻值发生明显的变化。
选购热敏电阻时,要注意两个参数---常用温度和对应阻值。
你必须明白你的系统一般是工作在哪些温度范围内。
比如鸿哥本节的程序是工作在室内常温范围内的,因此我选购的热敏电阻型号是“25度/10K”,“25度/10K”表示当温度是25度时它的阻值刚好是10K。
(1)功能需求:利用两位数码管显示当前环境的温度,温度范围是0度到53度。
误差+-1度。
(2)硬件原理:(a)动态扫描两位数码管的电路请参考第二十一节。
(d)分压电路描述:热敏电阻一端接电源5V,热敏电阻的另一端跟一个3.3K的精密电阻串接起来,3.3K电阻的另一端接电源地VSS,再利用PIC单片机的一个AD口连接热敏电阻和3.3K电阻的中间连接点,单片机只要读取它们连接点的电压即可计算出热敏电阻的阻值,再通过查表就可以知道当前的温度值。
(3)源码适合的单片机: PIC16F73,晶振为3.579545MHz。
(4)“25度/10K”热敏电阻的“阻值--温度”表:请下载本节的附件。
(5)单片机的C语言源代码讲解如下:#include<pic.h>#define seg_0_dr RB6 //任意7个IO口接数码管的seg引脚#define seg_1_dr RB5#define seg_2_dr RB4#define seg_3_dr RB3#define seg_4_dr RC7#define seg_5_dr RB0#define seg_6_dr RB1#define com_left_dr RB2 //任意2个IO口接数码管的com引脚#define com_right_dr RB7void initial();//初始化void delay1(unsigned int de) ;//小延时程序,时间不宜太长,因为内部没有喂看门狗void display_drive(); //数码管驱动程序,放在定时中断里void display_seg(unsigned char seg); //编码转换程序,放在display_drive里void AD_conv(); //AD转换与查表处理程序unsigned char number_left=0; //左边数码管显示的内容unsigned char number_right=0; //右边数码管显示的内容unsigned char dis_step=1; //扫描的步骤unsigned int ad_click_dly=0; //每次采集AD的时间间隔。
[PIC单片机]吴坚鸿单片机程序风格赏析【4】
[PIC单片机]吴坚鸿单片机程序风格赏析【4】第二十九节:时间篇--利用时钟芯片DS1302实现时钟功能开场白:DS1302是最常用的时钟芯片。
价格不贵。
仅仅占用单片机3个IO口。
精度能满足大多数要求不高的项目。
它有两路独立电源输入,我们只要在其中一路电源上挂一个纽扣电池就可以实现掉电时钟继续跑的功能。
当然,纽扣电池作为备用电源必须比主电源的电压低一点,一个纽扣电池可以备用3年,另外,DS1302还给我们预留了一片RAM区,我们可以把一些数据存入到DS1302,只要DS1302的电池有电,那么它就相当于一个EPROM。
这个RAM区有什么用呢?因为RAM区的数据只要一掉电,所有的数据都会变成0x00或者0xff,也就是数据掉电会丢失,我们可以利用这个特点,可以在里面存入标志位数据,一旦发现这个数据改变了,就知道时钟的数据需要重新设置过,或者说明电池没电了。
在移植本驱动程序中,有一个地方最容易出错,就是DS1302芯片的数据线DIO。
我们编程时要特别留意这个IO口什么时候作为数据输入,什么时候作为数据输出,以便及时更改方向寄存器。
对于51单片机,IO口在读取数据之前,要先置1。
(1)功能需求:(a) 利用两位数码管,一共分3个窗口显示。
第1个窗口实时显示秒的时间,第2个窗口实时显示分的时间,第3个窗口实时显示小时的时间。
(b) 利用一个独立按键,专门用来在3个窗口之间轮流切换。
开机上电默认显示第1个窗口(秒),按一次按键后切换到第2个窗口(分),再按一次就切换到第3个窗口(小时),再按则又切换回第1个窗口(秒),依次循环。
(c) 刚开机上电时,先检查时钟芯片的数据是否由于电池没电的原因被清零,如果是被清零了,那么就要把起始时间重新设置为13年5月2日12点50分36秒。
开机上电默认显示第1个窗口(秒)。
(2)硬件原理:(a) 独立按键的电路请参考第二节的内容。
(b) 动态扫描两位数码管的电路请参考第二十一节。
单片机c51程序设计
单片机c51程序设计单片机C51程序设计是一门结合了硬件知识和软件编程技能的学科,它广泛应用于自动化控制、智能设备、嵌入式系统等领域。
C51单片机是指使用C语言进行编程的8051系列单片机,它具备丰富的指令集和灵活的编程方式。
下面将从单片机的基本概念、C51编程基础、程序设计步骤以及实例分析等方面进行介绍。
单片机的基本概念单片机,又称微控制器,是一种集成了处理器核心、存储器、输入/输出接口等的微型计算机系统。
它具有体积小、功耗低、成本低、可靠性高等特点。
C51单片机是基于Intel 8051微控制器架构的,具有8位数据总线和16位地址总线,支持多种外设接口。
C51编程基础1. C语言基础:熟悉C语言的基本语法,如变量声明、条件语句、循环语句、函数等。
2. 数据类型:了解C51单片机支持的数据类型,包括特有寄存器位操作。
3. 内存结构:掌握C51单片机的内存结构,包括内部RAM、外部RAM、程序存储器等。
4. 中断系统:理解中断的概念和中断服务程序的编写。
5. 定时器/计数器:了解如何使用单片机的定时器/计数器进行时间控制和事件计数。
程序设计步骤1. 需求分析:明确程序设计的目标和功能需求。
2. 系统设计:设计系统的整体架构,包括硬件连接和软件模块划分。
3. 编写代码:根据设计编写C51程序代码,包括初始化代码、主函数、中断服务程序等。
4. 调试:使用仿真软件或实际硬件对程序进行调试,确保程序正确运行。
5. 优化:根据调试结果对程序进行优化,提高效率和稳定性。
6. 测试:进行全面的测试,确保程序在各种条件下都能稳定运行。
实例分析以一个简单的LED闪烁程序为例,介绍C51程序设计的基本流程:```c#include <reg51.h>// 定义LED连接的端口#define LED_PORT P1void delay(unsigned int ms) {unsigned int i, j;for (i = ms; i > 0; i--)for (j = 110; j > 0; j--);}void main() {while (1) {LED_PORT = 0xFF; // 关闭所有LED灯delay(500); // 延时500msLED_PORT = 0x00; // 打开所有LED灯delay(500); // 延时500ms}}```在这个例子中,我们首先包含了8051单片机的寄存器定义文件`reg51.h`,定义了LED灯连接的端口为P1。
C51程序
if(jian==0) {delay(10); {if(num>0) {num--; while(!jian);
} else
{num=0; } } } jisuan(); } } 16,双开关,每个开关两位数 #include<reg51.h> #define uint unsigned int sbit k1=P1^4; sbit k2=P1^5; void delay() { uint i,j; for(j=3;j>0;j--) for(i=110;i>0;i--); } void main() { while(1) { if(k1==0) { P2=0x7f; P0=0xb0; delay(); P2=0xbf; P0=0xf8; delay(); } } { if(k2==0)
uchar ge,shi,bai; void delay(uint x) {uint i,j; for(j=x;j>0;j--) for(i=110;i>0;i--); } void jisuan() {bai=num/100; shi=num%100/10; ge=num%100%10; } void chu() {ge=0; shi=0; bai=0; num=0; } void xianshi() {P2=0x7f; P0=table[ge]; delay(1); P2=0xbf; P0=table[shi]; delay(1); P2=0xdf; P0=table[bai]; delay(1); } void main() {chu(); while(1)
[PIC单片机] 吴坚鸿单片机程序风格赏析【2】
第十一节:鸿哥单色液晶屏三大类定律(KS0107驱动12864屏)(1)开场白:我曾经做过一年的液晶屏工程师,“出家”做自由职业者之后我又在很多项目上应用液晶屏。
深圳很多液晶模块公司都是用我帮他们做的测试程序。
不管什么品种的单色屏我都能玩得转。
谦虚一点说就是,在单色液晶驱动程序这方面,吴坚鸿在全国绝对排名在前三名之内(如果不谦虚地说我就号称第一了,呵呵)。
接下来我要介绍一下我的新发现,单色屏驱动程序的三大类定律。
市面上有各种各样的单色屏,什么点阵,段码等等,但是都逃不出我总结的三大类定律。
读者只要学会了鸿哥的三大类定律,以后任何单色屏对于你们来说都是浮云。
想要驱动液晶屏,只要知道怎么样在任何一个地方(X轴与Y轴坐标)显示一个基本单位就够了。
在单色液晶屏领域,这个显示的基本单位只有三种类型,也就是我总结的三大类定律。
第一大类定律:纵向显示八个点的类型。
这类液晶屏在纵向上以八个点(一个字节)为基本单位,因此Y坐标数值的最大范围是纵向上的点阵数除以八,然后再减去一(因为从零开始)。
而X坐标数值的最大范围就直接是横向上的点阵数减去一(因为从零开始)。
第二大类定律:横向显示八个点的类型。
这类液晶屏在横向上以八个点(一个字节)为基本单位,因此X坐标数值的最大范围是横向上的点阵数除以八,然后再减去一(因为从零开始)。
而Y坐标数值的最大范围就直接是纵向上的点阵数减去一(因为从零开始)。
第三大类定律:任意位置显示一个点的类型。
这类液晶屏在任意位置上以一个点为基本单位,因此X坐标数值的最大范围就直接是横向上的点阵数减去一(因为从零开始)。
而Y坐标数值的最大范围就直接是纵向上的点阵数减去一(因为从零开始)。
下面,我以驱动芯片为KS0107的12864液晶屏为例子,来介绍一下第一大类定律:纵向显示八个点的类型。
12864液晶屏实际上是由左右两块6464液晶屏合并在一起的,然后通过两根IO口来片选不同的6464液晶屏。
因此,我们只要弄懂了一块6464液晶屏的显示方法就够了。
C51使用详解
Keil C51使用详解V1.0©电子设计世界版权所有欢迎转贴请勿修改并注明出处保留一切权利第一章 Keil C51开发系统基本知识 (6)第一节系统概述 (6)第二节Keil C51单片机软件开发系统的整体结构 (6)第三节Keil C51工具包的安装 (7)1. C51 for Dos 72. C51 for Windows的安装及注意事项 (7)第四节Keil C51工具包各部分功能及使用简介 (7)1. C51与A51. 72. L51和BL51. 83. DScope51Tscope51及Monitor51. 84. Ishell及uVision. 9第二章 Keil C51软件使用详解 (10)第一节Keil C51编译器的控制指令 (10)1. 源文件控制类 (10)2. 目标文件(Object)控制类 (10)3. 列表文件(listing)控制类 (10)第二节dScope51的使用 (11)1. dScope51 for Dos 112. dScope for Windows 12第三节Monitor51及其使用 (13)1. Monitor51对硬件的要求 (13)2. Mon51的使用 (13)3. MON51的配置 (13)4. 串口连接图 (13)5. MON51命令及使用 (14)第四节集成开发环境(IDE)的使用 (14)1. Ishell for Dos的使用 (14)2. uVision for windows的使用 (15)第三章 Keil C51 vs 标准C.. 15第一节Keil C51扩展关键字 (15)第二节内存区域(Memory Areas) (16)1. Pragram Area (16)2. Internal Data Memory: 163. External Data Memory. 164. Speciac Function Register Memory. 16第三节存储模式 (16)1. Small模式 (16)2. Compact模式 (17)3. large模式 (17)第四节存储类型声明 (17)第五节变量或数据类型 (17)第六节位变量与声明 (17)1. bit型变量 (17)2. 可位寻址区说明20H2FH.. 18第七节Keil C51指针 (18)1. 一般指针 (18)2. 存储器指针 (18)3. 指针转换 (18)第八节Keil C51函数 (19)1. 中断函数声明 (19)2. 通用存储工作区 (19)3. 选通用存储工作区由using x声明见上例 (19)4. 指定存储模式 (19)5. #pragma disable. 196. 递归或可重入函数指定 (19)7. 指定PL/M51函数 (20)第四章 Keil C51高级编程 (20)第一节绝对地址访问 (20)1. 绝对宏 (20)2. _at_关键字 (21)3. 连接定位控制 (21)第二节Keil C51与汇编的接口 (21)1. 模块内接口 (21)2. 模块间接口 (21)第三节Keil C51软件包中的通用文件 (22)1. 动态内存分配 (22)2. C51启动文件STARTUP.A51. 223. 标准输入输出文件 (25)4. 其它文件 (25)第四节段名协定与程序优化 (25)1. 段名协定(Segment Naming Conventions) 252. 程序优化 (25)第五章 Keil C51库函数参考 (26)第一节本征库函数(intrinsic routines)和非本征证库函数 (26)第二节几类重要库函数 (26)1. 专用寄存器include文件 (26)2. 绝对地址include文件absacc.h. 263. 动态内存分配函数位于stdlib.h中 (27)4. 缓冲区处理函数位于string.h”中 (27)5. 输入输出流函数位于stdio.h”中 (27)第三节Keil C51库函数原型列表 (27)1. CTYPE.H.. 272. INTRINS.H.. 273. STDIO.H.. 284. STDLIB.H.. 285. STRING.H.. 28第六章 Keil C51例子Hello.c.. 29第一节uVision for Windows的使用步骤 (29)第二节Ishell for Dos使用步骤 (30)第七章 Keil C51的代码效率 (30)第一节存储模式的影响 (30)第二节程序结构的影响 (31)第八章 dScope for Windows使用详解 (32)第一节概述 (32)1. 主窗口Mainframe Window (32)2. 调试窗口DEBUG Window (32)3. 命令窗口Command Window (32)4. 观察窗口Watch Window (32)5. 寄存器窗口Registe Window (32)6. 串口窗口Serical Windows (32)7. 性能分析窗口 (32)8. 内存窗口Memory Window (32)9. 符号浏览窗口Symbol Browser Window (33)10. 调用线窗口Call Stack Window (33)11. 代码覆盖窗口 (33)12. 外围设备窗口(peripherals) 33第二节dScope for Windows基本操作 (33)1. 指定初始化文件 (33)2. 观察变量 (33)3. 显示RAM的值 (34)4. 观察堆栈 (34)5. 中断处理程序调试 (34)6. 性能分析Performance Analyzer PA (34)第三节dScope for Windows命令文件的编制 (34)1. 地址空间及地址空间类型 (34)2. 常量 (35)3. 变量 (36)4. 运算符 (38)5. 表达式 (38)6. 数组 (38)7. 结构和联合 (38)8. 指针 (38)9. dScope命令语句 (38)10. 函数 (43)第一章 Keil C51开发系统基本知识第一节系统概述Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统与汇编相比C语言在功能上结构性可读性可维护性上有明显的优势因而易学易用用过汇编语言后再使用C来开发体会更加深刻Keil C51软件提供丰富的库函数和功能强大的集成开发调试工具全Windows 界面另外重要的一点只要看一下编译后生成的汇编代码就能体会到Keil C51生成的目标代码效率非常之高多数语句生成的汇编代码很紧凑容易理解在开发大型软件时更能体现高级语言的优势下面详细介绍Keil C51开发系统各部分功能和使用第二节Keil C51单片机软件开发系统的整体结构C51工具包的整体结构如图(1)所示其中uVision与Ishell分别是C51 for Windows和for Dos的集成开发环境(IDE)可以完成编辑编译连接调试仿真等整个开发流程开发人员可用IDE本身或其它编辑器编辑C或汇编源文件然后分别由C51及A51编译器编译生成目标文件(.OBJ)目标文件可由LIB51创建生成库文件也可以与库文件一起经L51连接定位生成绝对目标文件(.ABS)ABS文件由OH51转换成标准的Hex文件以供调试器dScope51或tScope51使用进行源代码级调试也可由仿真器使用直接对目标板进行调试也可以直接写入程序存贮器如EPROM中图(1) C51工具包整体结构图第三节Keil C51工具包的安装1. C51 for Dos在Windows下直接运行软件包中DOS\C51DOS.exe然后选择安装目录即可完毕后欲使系统正常工作须进行以下操作(设C:\C51为安装目录)修改Autoexec.bat加入path=C:\C51\BinSet C51LIB=C:\C51\LIBSet C51INC=C:\C51\INC然后运行Autoexec.bat2. C51 for Windows的安装及注意事项在Windows下运行软件包中WIN\Setup.exe最好选择安装目录与C51 for Dos 相同这样设置最简单(设安装于C:\C51目录下)然后将软件包中crack目录中的文件拷入C:\C51\Bin目录下第四节Keil C51工具包各部分功能及使用简介1. C51与A51(1) C51C51是C语言编译器其使用方法为C51 sourcefile[编译控制指令]或者C51 @ commandfile其中sourcefile为C源文件(.C)大量的编译控制指令完成C51编译器的全部功能包控C51输出文件C.LST.OBJ.I和.SRC文件的控制源文件(.C)的控制等详见第五部分的具体介绍而Commandfile为一个连接控制文件其内容包括.C源文件及各编译控制指令它没有固定的名字开发人员可根据自己的习惯指定它适于用控制指令较多的场合(2) A51A51是汇编语言编译器使用方法为A51 sourcefile[编译控制指令]或A51 @ commandfile其中sourcefile为汇编源文件(.asm或.a51)而编译控制指令的使用与其它汇编如ASM 语言类似可参考其他汇编语言材料Commandfile同C51中的Commandfile类似它使A51使用和修改方便2. L51和BL51(1) L51L51是Keil C51软件包提供的连接/定位器其功能是将编译生成的OBJ文件与库文件连接定位生成绝对目标文件(.ABS)其使用方法为L51 目标文件列表[库文件列表] [to outputfile] [连接控制指令]或L51 @Commandfile源程序的多个模块分别经C51与A51编译后生成多个OBJ文件连接时这些文件全列于目标文件列表中作为输入文件如果还需与库文件(.LiB)相连接则库文件也必须列在其后outputfile为输文件名缺少时为第一模块名后缀为.ABS 连接控制指令提供了连接定位时的所有控制功能Commandfile为连接控制文件其具体内容是包括了目标文件列表库文件列表及输出文件连接控制命令以取代第一种繁琐的格式由于目标模块库文件大多不止1个因而第2种方法较多见这个文件名字也可由使用者随意指定(2) Bl51BL51也是C51软件包的连接/定位器其具有L51的所有功能此外它还具有以下3点特别之处a. 可以连接定位大于64kBytes的程序b. 具有代码域及域切换功能(CodeBanking & Bank Switching)c. 可用于RTX51操作系统RTX51是一个实时多任务操作系统它改变了传统的编程模式甚至不必用main( )函数单片机系统软件向RTOS发展是一种趋势这种趋势对于186和386及68K系列CPU更为明显和必须对8051因CPU较为简单程序结构等都不太复杂RTX51作用显得不太突出其专业版软件PK51软件包甚至不包括RTX51Full 而只有一个RTX51TINY版本的RTOS RTX51 TINY适用于无外部RAM的单片机系统因而可用面很窄在本文中不作介绍Bank switching技术因使用很少也不作介绍3. DScope51Tscope51及Monitor51(1) dScope51dScope51是一个源级调试器和模拟器它可以调试由C51编译器A51汇编器PL/M-51编译器及ASM51汇编器产生的程序它不需目标板for windows也可通过mon51接目标板只能进行软件模拟但其功能强大可模拟CPU及其外围器件如内部串口外部I/O及定时器等能对嵌入式软件功能进行有效测试其使用方法为DS51[debugfile][INIT(initfile)]其中debugfile是一个Hex格式的8051文件即待调试的文件其为可选的可在进入dScope51后用load命令装入Initfile为一个初使化文件它在启动dScope51后在debugfile装入前装入装有一些dScope的初使化参数及常用调试函数等下面是一个dScope.ini文件(for dos)的内容Load ..\..\ds51\8051.iofMap 0,0xffffdScope51 for Windows则直接用鼠标进入然后用load装入待调文件(2) tScope51与dScope51不同的是Scope51必须带目标板目前它可以通过两种方式访问目标板(1) 通过EMul51在线仿真器tScope51为该仿真器准备了一个动态连接文件EMUL51.IOT但该方法必须配合该仿真器(2) 通过Monitov51监控程序这种方法是可行的tScope51为访问Monitor51专门带有MON51.IOT连接程序使用时可通过串口及监控程序来调试目标板其使用方法为TS51[INIT(file_name.ini)]其中file_name.ini为一个初使化文件进入TS51后必须装入IOT文件可用的有MON51.IOT及EMUL51.IOT两种如装入MON51.IOTLoad.C:\C51\TS51\MON51.IOT CPUTYPE(80517)可惜的是tScope51只有for Dos的版本(3) Monitor 51Monitor51是一个监控程序通过PC机的串口与目标板进行通信Monitor操作需要MON51或dScope51 for Windows,后面部分将对Monitor51做较为详细的介绍4. Ishell及uVision(1) Ishell for Dos这是一个for Dos的IDE直接在命令行键入Ishell则进入该环境它使用简单方便其命令行与DOS命令行具有同样的功能对单模块的Project直接由菜单进行编译连接对多模块的project则通过批处理BAT文件进行编译连接然后通过菜单控制由dScope51或tScope51对程序进行调试因为是for dos的不做太详细介绍(2) uVision for WindowsuVision for Windows是一个标准的Windows应用程序它是C51的一个集成软件开发平台具有源代码编辑project管理集成的make等功能它的人机界面友好操作方便是开发者的首选具体配置及使用见第五部分第二章 Keil C51软件使用详解第一节Keil C51编译器的控制指令C51编译器的控制指令分为三类源文件控制类目标文件控制类及列表控制类1. 源文件控制类NOEXTEND C51源文件不允许使用ANSI C扩展功能DEFINE(DF)定义预处理(在C51命令行)2. 目标文件(Object)控制类COMPACT LARGE SMALL 选编译模式DEBUG(DB) 包含调试信息以供仿真器或dSCope51使用NOAMAKE(NOAM) 禁止AutoMake信息记录NOREGPARMS 禁止用寄存器传递参数OBJECTEXTEND(OE) Object文件包含附加变量类型信息OPTIMIZE(OT) 指定优化级别REGFILE(RF) 指定一个寄存器使用的文件以供整体优化用REGISTERBANK(RB) 指定一个供绝对寄存器访问的寄存器区名SRC 不生成目标文件只生成汇编源文件其它控件不常用3. 列表文件(listing)控制类CODE(CD)向列表文件加入汇编列表LISTINCLUDE(LC)显示indude文件SYMBOLS(SB)列表文件包括模块内所有符号的列表WARNINGLEVEL(WL)选择警告级别第二节dScope51的使用1. dScope51 for Dos总的来说dScope51具有以下特性高级语言显示模式集成硬件环境模拟单步或GO”执行模式存储器寄存器及变量访问Watch表达式之值函数与信号功能下面具体说明在进入dScope51 for Dos之后如何实现上述功能dScope51采用下拉菜单格式和窗口显示控制共有language serial exe register四个窗口其中exe为命令行窗口language为程序窗口serial为串口窗register为寄存器窗(1) 高级语言显示模式单击主菜单中的View”第一栏中的三条命令Highlevel”Mixed”Assembly”分别对所装入的程序按照高级混合级及汇编级三种方式显示以方便调试使用(2) 集成硬件环境模拟显示主菜单中Peripheral”各条能显示模拟硬件环境的状态其中i/o Port显示各I/O口之值对8031而言SFR中的P1P2P3P0与引脚之值分别列出Interrupt显示5个中断源的入口模式是否允许优先级等中断状态Timer显示各定时/计数器的模式初始值状态等int Message中断信息允许如为允许(“>>”出现)则当中断申请时显示中断源信息比如当中断发生时会显示“interrupt Timer 0 occured”等A/D converter显示A/D转换器状态无时则提示无Serial串口信息显示包括串口模式波特产等Other其它器件如为8031则显示无(3) 单步或Go”执行F8”单步执行F5”全速执行到断点或选主菜单中Trace单步执行CPU中的Go全速执行(4) 存储器寄存器及变量访问外部存储器管理MAP菜单设置(set)取消(reset)显示(Display)处理可用存储修改Code代码ASM命令存储器显示命令 D 类别为(X D I B C)修改存储器命令 E 有以下几种命令EB EC EI EL EF EP复杂数据类型显示Object命令用以显示结构或数组的内容欲使此命令有效C51编译器必须有DB及OBJECTEXTEND两条反汇编命令U(5) “Watch”表达式之值在View菜单的Watch”一栏中有四项其中包括定义Watch Point(Define)删除Watch Point(remove,kill all)及自动更新选项也可用WS WK等命令代替下面具体看表达式类型dScope51一次最多可设16个WtchPoint表达式显示于Watch Window之中表达式可以是简单变量也可是复杂数据类型如结构数组和指向结构的指针等例如>WS *ptime>WS ptime hour>WS some_record[o]analog等等(6) 关于.IOF文件启动DS51后必须装入.IOF文件才能使CPU及Peripheral各项起作用这个函数的使用是依据8051系列CPU的不同特点装入8051各CPU硬件设备模拟驱动文件比如8031CPU就必须load DS51目录下的8051.IOF2. dScope for WindowsdScope for windows具有dScope for dos的全部功能此外它还具有以下明显的优点(1) 标准的Windows界面操作更容易更简单(2) 常用操作多用对话框而非Dos的行命令方式(3) 窗口资源更加丰富存储器窗口覆盖率分析运行状态分析窗口加强了调因为dScope for Windows功能强大具体操作在第八章详细介绍第三节Monitor51及其使用1. Monitor51对硬件的要求(1) 硬件系统为51系列CPU(2) 带5K外部程序存储器(从O地址开始)存放Monitor51程序(3) 256Bytes的外部数据存储器以及5K的跟踪缓冲区此外外部数据存储器必须足够容纳所有应用程序代码及数据且所有外部数据存储器必须为冯诺伊曼存储器即能一致访问XDATA与Code空间(4) 一个定时器作为波特率发生器供串口使用(5) 6 Bytes的空余堆栈2. Mon51的使用Mon51的使用途径有三种方式(1) Dos行命令方式即先用install对MON51进行配置然后用MON51进入Monitor状态启用各种命令对Monitor51进行调试(2) tScope51方式启动tScope51装入TS51目录下的MON51.IOT驱动文件与目标板通信(3) dScope51 for Windows方式在选CPU驱动文件时选MON51.dll”则检查目标板并进入MON51状态3. MON51的配置(1) MON51 for Dos的配置运行install文件(在MON51目录下)不同的参数可以配置不同的硬件环境INSTALL Serialtype [xdstastart[codestart[bank][PROMCHECK]]]具体说明见MON51帮助文件或使用手册(2) MON51 for Windows的配置在启用MON51.dll时会使得系统自动检查目标板连接如配置不对则弹出Configuration”对话框设置PC串口波特率等完毕单击apply”有效4. 串口连接图收发交叉互连RTS CTS直连DSR DTR直连具体引脚排列参考串口资料5. MON51命令及使用详细的MON51命令可参阅帮助第四节集成开发环境(IDE)的使用1. Ishell for Dos的使用进入Ishell之后看到两个窗口一个是文件窗口一个是Dos命令行窗口窗口上方是下拉式的命令菜单其中的Files控制文件窗口的显隐使用Ishell第一步就是配置系统即要学习两个文件的修改与创建(1) Ishell.CFG文件每一个project都有一个Ishell.CFG其中存放有Option菜单和Setup菜单下的部分信息Bell enabled Monochrome enabled Editor Selected CRT Lines target enviroment name of user edit Automatic load for configuration enabled file window enabled file specification for file window translate command line controls project name 等对每个project都必须设置以上信息然后存盘setup”的的save”这样才可正式开始下面工作(2) IShell.col文件对IDE颜色设置如不改动可以缺省为主(3) CDF文件该文件位于BIN目录下每一文件定义一组外部函数工具包即定义外部环境如8051.CDF USER.CDF等开发者可修改CDF文件供自己使用至于CDF文件内容可查看一下8051.CDF即可知道注意.CDF文件是Ishell系统的核心所在不同的CDF文件可使本IDE适用于不同的编译连接系统即本IDE并不仅适于C51下面谈一谈Automake工具C51的Automake是一个project管理器在8051工具包中以OBJECT文件形式保留了一个project的信息AutoMake用这些信息来进行project管理一旦手工建立一个project Automake可生成一个新的OBJECT AutoMake利用此文件来编译那些修改过的文件Automake支持C51A51L51/BL51C166A166L166等编译连接器点中主菜单中的Automake即运行本工具Ishell for Dos使用比较繁琐推荐使用uVision for windows2. uVision for windows的使用uVision是一个标准的windows应用程序其编译功能文件处理功能project 处理功能窗口功能以及工具引用功能(如A51C51PL/M41BL51 dScope等)等都较Ishell for Dos要强得多uVision采用BL51作连接器因为BL51兼容L51所以一切能在Dos下工作的project都可以到uVision中进行连接调试uVision采用dScope for windows作调试器该调试器支持MON51及系统模拟两种方式功能较for DOS要强大好用调试功能强大注意(1) Option菜单下的各项要会使用其中A51C51PL/M51BL51定义各文件所使用的编译连接控制指令dScope定义一个dScope初始化文件Make则是定义一个make文件(2) 进入调试是在RUN菜单下运行dScope(3) project中包括新建打开修改更新编译连接等poject处理具体使用可参考后面的例子第三章 Keil C51 vs 标准C深入理解并应用C51对标准ANSIC的扩展是学习C51的关键之一因为大多数扩展功能都是直接针对8051系列CPU硬件的大致有以下8类8051存储类型及存储区域存储模式存储器类型声明变量类型声明位变量与位寻址特殊功能寄存器(SFR)C51指针函数属性具体说明如下(8031为缺省CPU)第一节Keil C51扩展关键字C51 V4.0版本有以下扩展关键字(共19个)_at_ idata sfr16 alien interrupt smallbdata large _task_ Code bit pdatausing reentrant xdata compact sbit data sfr第二节内存区域(Memory Areas)1. Pragram Area由Code说明可有多达64kBytes的程序存储器2. Internal Data Memory:内部数据存储器可用以下关键字说明data直接寻址区为内部RAM的低128字节00H7FHidata间接寻址区包括整个内部RAM区00H FFHbdata可位寻址区20H2FH3. External Data Memory外部RAM视使用情况可由以下关键字标识xdata可指定多达64KB的外部直接寻址区地址范围0000H0FFFFHpdata能访问1页(25bBytes)的外部RAM主要用于紧凑模式(Compact Model) 4. Speciac Function Register Memory8051提供128Bytes的SFR寻址区这区域可位寻址字节寻址或字寻址用以控制定时器计数器串口I/O及其它部件可由以下几种关键字说明sfr字节寻址比如sfr P0=0x80;为PO口地址为80H后H FFH之间的常数sfr16字寻址如sfr16 T2=0xcc;指定Timer2口地址T2L=0xcc T2H=0xCD sbit位寻址如sbit EA=0xAF;指定第0xAF位为EA即中断允许还可以有如下定义方法sbit 0V=PSW^2(定义0V为PSW的第2位)sbit 0V0XDO^2(同上)或bit 0V-0xD2(同上)第三节存储模式存储模式决定了没有明确指定存储类型的变量函数参数等的缺省存储区域共三种1. Small模式所有缺省变量参数均装入内部RAM优点是访问速度快缺点是空间有限只适用于小程序2. Compact模式所有缺省变量均位于外部RAM区的一页(256Bytes)具体哪一页可由P2口指定在STARTUP.A51文件中说明也可用pdata指定优点是空间较Small为宽裕速度较Small慢较large要快是一种中间状态3. large模式所有缺省变量可放在多达64KB的外部RAM区优点是空间大可存变量多缺点是速度较慢提示存储模式在C51编译器选项中选择第四节存储类型声明变量或参数的存储类型可由存储模式指定缺省类型也可由关键字直接声明指定各类型分别用code,data,idata,xdata,pdata说明例data uar1char code array[ ]hello!”;unsigned char xdata arr[10][4][4]第五节变量或数据类型C51提供以下几种扩展数据类型bit 位变量值为0或1sbit 从字节中定义的位变量0或1sfr sfr字节地址0255sfr16 sfr字地址065535其余数据类型如char,enum,short,int,long,float等与ANSI C相同第六节位变量与声明1. bit型变量bit型变量可用变量类型函数声明函数返回值等存贮于内部RAM20H2FH 注意(1) 用pragma disable说明函数和用usign”指定的函数不能返回bit值(2) 一个bit变量不能声明为指针如bit *ptr是错误的(3) 不能有bit数组如bit arr[5]错误2. 可位寻址区说明20H2FH可作如下定义int bdata ichar bdata arr[3]然后sbit bito in0sbit bit15=I^15sbit arr07=arr[0]^7sbit arr15=arr[i]^7第七节Keil C51指针C51支持一般指针(Generic Pointer)和存储器指针(Memory_Specific Pointer).1. 一般指针一般指针的声明和使用均与标准C相同不过同时还可以说明指针的存储类型例如long * state;为一个指向long型整数的指针而state本身则依存储模式存放char * xdata ptr ptr为一个指向char数据的指针而ptr本身放于外部RAM区以上的long,char等指针指向的数据可存放于任何存储器中一般指针本身用3个字节存放分别为存储器类型高位偏移低位偏移量2. 存储器指针基于存储器的指针说明时即指定了存贮类型例如char data * str;str指向data区中char型数据int xdata * pow; pow指向外部RAM的int型整数这种指针存放时只需一个字节或2个字节就够了因为只需存放偏移量3. 指针转换即指针在上两种类型之间转化当基于存储器的指针作为一个实参传递给需要一般指针的函数时指针自动转化如果不说明外部函数原形基于存储器的指针自动转化为一般指针导致错误因而请用include”说明所有函数原形可以强行改变指针类型第八节Keil C51函数C51函数声明对ANSI C作了扩展具体包括1. 中断函数声明中断声明方法如下void serial_ISR () interrupt 4 [using 1]{/* ISR */}为提高代码的容错能力在没用到的中断入口处生成iret语句定义没用到的中断/* define not used interrupt, so generate "IRET" in their entrance */void extern0_ISR() interrupt 0{} /* not used */void timer0_ISR () interrupt 1{} /* not used */void extern1_ISR() interrupt 2{} /* not used */void timer1_ISR () interrupt 3{} /* not used */void serial_ISR () interrupt 4{} /* not used */2. 通用存储工作区3. 选通用存储工作区由using x声明见上例4. 指定存储模式由small compact 及large说明例如void fun1(void) small { }提示small说明的函数内部变量全部使用内部RAM关键的经常性的耗时的地方可以这样声明以提高运行速度5. #pragma disable在函数前声明只对一个函数有效该函数调用过程中将不可被中断6. 递归或可重入函数指定在主程序和中断中都可调用的函数容易产生问题因为51和PC不同PC使用堆栈传递参数且静态变量以外的内部变量都在堆栈中而51一般使用寄存器传递参数内部变量一般在RAM中函数重入时会破坏上次调用的数据可以用以下两种方法解决函数重入a在相应的函数前使用前述#pragma disable”声明即只允许主程序或中断之一调用该函数b将该函数说明为可重入的如下void func(param...) reentrant;KeilC51编译后将生成一个可重入变量堆栈然后就可以模拟通过堆栈传递变量的方法由于一般可重入函数由主程序和中断调用所以通常中断使用与主程序不同的R 寄存器组另外对可重入函数在相应的函数前面加上开关#pragma noaregs”以禁止编译器使用绝对寄存器寻址可生成不依赖于寄存器组的代码7. 指定PL/M51函数由alien指定第四章 Keil C51高级编程本章讨论以下内容绝对地址访问C与汇编的接口C51软件包中的通用文件段名转换与程序优化第一节绝对地址访问C51提供了三种访问绝对地址的方法1. 绝对宏在程序中用include<absacc.h>”即可使用其中定义的宏来访问绝对地址包括CBYTE XBYTE PWORD DBYTE CWORD XWORD PBYTE DWORD具体使用可看一看absacc.h便知例如rval=CBYTE[0x0002];指向程序存贮器的0002h地址rval=XWORD [0x0002];指向外RAM的0004h地址2. _at_关键字直接在数据定义后加上_at_ const即可但是注意(1)绝对变量不能被初使化(2)bit型函数及变量不能用_at_指定例如idata struct link list _at_ 0x40;指定list结构从40h开始xdata char text[25b] _at_0xE000指定text数组从0E000H开始提示如果外部绝对变量是I/O端口等可自行变化数据需要使用volatile关键字进行描述请参考absacc.h3. 连接定位控制此法是利用连接控制指令code xdata pdata \data bdata对段地址进行如要指定某具体变量地址则很有局限性不作详细讨论第二节Keil C51与汇编的接口1. 模块内接口方法是用pragma语句具体结构是#pragma asm汇编行#pragma endasm这种方法实质是通过asm与ndasm告诉C51编译器中间行不用编译为汇编行因而在编译控制指令中有SRC以控制将这些不用编译的行存入其中2. 模块间接口C模块与汇编模块的接口较简单分别用C51与A51对源文件进行编译然后用L51将obj文件连接即可关键问题在于C函数与汇编函数之间的参数传递问题C51中有两种参数传递方法(1) 通过寄存器传递函数参数最多只能有3个参数通过寄存器传递规律如下表参数数目Char Int long,float 一般指针1 R7 R6 & R7 R4R7 R1R32 R5 R4 & R5 R4R7 R1R33 R3 R2 & R3 R1R3(2) 通过固定存储区传递(fixed memory)这种方法将bit型参数传给一个存储段中function_name?BIT将其它类型参数均传给下面的段function_name?BYTE,且按照预选顺序存放至于这个固定存储区本身在何处则由存储模式默认(3) 函数的返回值函数返回值一律放于寄存器中有如下规律Return type Registev 说明Bit 标志位由具体标志位返回char/unsigned charR7 单字节由R7返回1_byte指针R6 & R7 双字节由R6和R7返回,MSB在R6 int/unsigned int2_byte指针long&unsigned long R4R7 MSB在R4, LSB在R7Float R4R7 32Bit IEEE格式一般指针R1R3 存储类型在R3 高位R2 低R1 (4) SRC控制该控制指令将C文件编译生成汇编文件(.SRC)该汇编文件可改名后生成汇编.ASM 文件再用A51进行编译第三节Keil C51软件包中的通用文件在C51\LiB目录下有几个C源文件这几个C源文件有非常重要的作用对它们稍事修改就可以用在自己的专用系统中1. 动态内存分配init_mem.C此文件是初始化动态内存区的程序源代码它可以指定动态内存的位置及大小只有使用了init_mem( )才可以调回其它函数诸如malloc calloc,realloc 等calloc.c此文件是给数组分配内存的源代码它可以指定单位数据类型及该单元数目malloc.c此文件是malloc的源代码分配一段固定大小的内存realloc.c此文件是realloc.c源代码其功能是调整当前分配动态内存的大小2. C51启动文件STARTUP.A51。
C51程序设计
C51程序设计C51程序设计是指通过C语言编写的用于C51单片机的程序。
C51单片机是一种基于8051架构的单片机,具有广泛的应用领域,如电子产品、嵌入式系统等。
在本文中,我将讲述C51程序设计的完整内容,并且给出1200多字的详细说明。
首先,C51单片机具有的特点主要有:易于学习和使用、低功耗、功能强大、扩展性好、体积小、性能稳定等。
C51单片机的硬件结构包括中央处理器(CPU)、存储器、输入输出(I/O)端口等。
中央处理器是C51单片机的核心部件,负责执行指令和控制系统的运行。
存储器用于存储数据和程序,包括随机存储器(RAM)和只读存储器(ROM)。
输入输出端口用于与外部设备进行数据交互,如LED灯、数码管、键盘等。
其次,C语言是一种高级程序设计语言,被广泛应用于嵌入式系统和各种应用程序的开发。
C语言的基本语法包括数据类型、变量、运算符、控制语句、函数等。
数据类型用于定义变量的类型,如整型、字符型、浮点型等。
变量是用于存储数据的标识符,可以在程序中进行赋值、读取和修改。
运算符用于进行各种算术、逻辑和位运算操作。
控制语句用于控制程序的执行流程,如条件语句、循环语句等。
函数是程序的基本模块,用于封装可重用的代码块。
在C51程序设计中,需要安装C51编译器,常用的有Keil C51、Keil C51是一种功能强大、易于使用的C51编译器,提供了丰富的库函数和调试工具,可以大大简化程序的开发和调试过程。
安装完编译器后,可以使用C语言编写C51程序,通过编译、烧写和运行等步骤,将程序加载到C51单片机中执行。
C51程序的设计步骤主要包括需求分析、程序设计、编码实现、编译和烧写、调试和测试等。
需求分析是明确程序的功能和性能要求,根据需求进行程序设计。
程序设计是将需求转化为具体的算法和数据结构,设计程序的模块和接口。
编码实现是根据设计的程序,使用C语言实现具体的功能和操作。
编译和烧写是将C源代码编译为可执行文件,并将可执行文件加载到C51单片机中执行。
c51程序设计
1Franklin C-51之袁州冬雪创作1.1Franklin C-51数据类型8051系列是8位机,因而不存在字节校准问题.这意味着数据布局成员是顺序放置的.数据类型的转换:当计算成果隐含着别的一种数据类型时,数据类型可以自动停止转换,例如,将一个位变量赋给一个整型变量时,位型值自动转换为整型值,有符号变量的符号也能自动停止处理.这些转换也可以用C语言的尺度指令停止人工转换.1.2数据类型的物理布局1.2.1bit“bit”类型只有1位,不允许有位指针和位数组.位对象始终位于8051 CPU的可寻址RAM空间.如果程序节制流允许,L51将位对象交迭. 1.2.2signed/unsigned char;data/idata/pdata 指针“char”类型标量和基于存贮器的“data/idata/pdata”指针具有1个字节长度(8 bits).1.2.3signed/unsigned int/short;xdata/code 指针“int”和“short”类型标量及指向xdata/code区域的指针具有2字节长度(16bits).整型值(或偏移)0x1234以下面方式保管在内存中:地址:+0 +1内容: 0x120x341.2.4signed/unsigned long“long”类型标量长为4个字节(32 bits),值0x12345678以下面方式放置:地址:+0+1+2+3内容: 0x12 0x34 0x56 0x781.2.5“一般”指针“一般”指针包含3个字节:2字节偏移和1字节存贮器类型:地址:+0 +1 +2内容:存贮器类型偏移高位偏移低位第一个字节代表了指针的存贮器类型,存贮器类型编码如下:存贮器类型 IDATA XDATA PDATADATACODE值 12 345使用其它类型值可以导致不成预测的程序动作.XDATA类型的0x1234地址作为指针暗示如下:地址:+0+1 +2内容: 0x02 0x12 0x34当用常数作指针时,必须注意正确定义存贮器类型和偏移.下例将值0x41写入相对地址为0x8000的外部数据存贮器:#defineXBYTE ((char *)0x20000L)XBYTE[0x8000]=0x41;上例中用其它常数索引或索引变量也起作用.这样,各种存贮器类型的相对地址可以一种非常有效的方式访问.但有一个破例,即SFR.注意:相对地址定义为“long”型常量,低16位包含偏移,高8位标了然xdata类型.为了暗示这种指针,必须用长整数来定义存贮器类型. C51编译器不检查指针常数,用户必须选择有实际意义的值.1.2.6float“float”类型为4个字节(32位),使用的格式与IEEE-754尺度(32位)具有24位精度,尾数的高位始终为“1”,因而不保管,位的分布如下:● 1位符号● 8位指数位● 23位尾数符号位是最高位,尾数为最低的位,内存中按字节存贮如下:地址:+0 +1 +2+3内容:MMMM MMMM MMMM MMMME MMM MMMMS EEE EEEE其中:S:符号位,1=负,0=正E:指数(在两个字节中),偏移为127M:23位尾数,最高位“1”浮点值——12.5的十六进制为0xC1480000,它按下面方式存贮:地址:+0+1+2+3内容: 0x00 0x00 0x48 0xc18051不包含捕获浮点错误(破例)的中断向量.用户软件因此必须对错误条件作出适当反应.下面推荐一种方法(也可以用其它靠得住法子):“union”用来保管浮点值,这个“union”必须包含一个“float”和一个“unsigned long”,以根据IEEE对错误作出响应.除了通常浮点值外,IEEE尺度可以出错的条件以下面二进制值暗示,为检查可以出现的计算错误,可在计算后停止检查.因为当执行一个运算时思索了每一个运算符的错误状态而且该状态被送到成果中.NaN0xFFFFFFF不是一个数+INF0x7F80000正无穷(正溢出)-INF0XFF80000负无穷(负溢出)1.3C-51 的扩大定义1.3.1特殊功能寄存器的声明MSC-51 系列包含多种寄存器,其中一些具有特殊功能,如定时器,端口的节制寄存器等,为了可以直接访问这些寄存器,C51编译器提供了一种定义的自主形式,这是需要的,因为这些定义与尺度C语言是不兼容的.为了支持这些特殊功能寄存器(SFR)的声明,引入了关键词“sfr”,语法如下:sfr-dcl:sfr sfr_name=int_constant例:sfr p0=0x80;sfr p1=0x90;必须注意的是“sfr”后不是一个地址而是一个名字.因此上例中名字P0和P1(port0和port1)定义为特殊功能寄存器并被赋予相应的相对地址,名字可按意愿自由选取,源文件中不该有先定义的sfr名字.“=”号后的地址必须是常数,不允许带有运算符的表达式,这个常数表达式必须在特殊功能寄存器的地址范围内,位于0X80到0XFF之间. 8051系列寄存器数量和类型是极其分歧的,因此建议将所有特此外“sfr”声明放入一个头文件,头文件包含8051一些系列成员中的SFR 定义.进一步的定义可由用户用一文件编辑器发生.1.3.2对SFR的16位数据访问在新的8051系列产品中,SFR在功能上常常组合为16位的,为了有效的访问这类SFR,使用定义“sfr16”,当“SFR”的高端直接位于低端后时,对SFR16位的访问是可以的.例如8052的定时器2就是这种情况,16位声明的语法与“sfr”相同,SFR低地址部分必须作为sfr16的地址:例:sfr16 T2=0xCC/*Timer2:T2L=0CCH,T2H=0CDH */sfr16 RCAP2=0xCA/*RCAP2L=0CAH,PCAP2H=0CBH */本例中,T2(由T2L和T2H组成)和RCAP2(由RCAP2L和RCAP2H 组成)被定义为16位SFR,即使在这种情况下,声明中的名字后仍不是赋值语句,而是一个SFR地址,高字节必须直接位于低字节之后,这种声明适用于所有新的SFR,但不克不及用于Timer0和Timer1. 1.3.3SBIT:特殊功能位声明在典型的8051应用问题中,常常需要单独访问SFR中的位,C51扩大功能使之成为可以,特殊位,象SFR一样,不与尺度C语言兼容,使用保存字“sbit”可访问位寻址对象.与SFR声明一样,用保存字“sbit”声明某些特殊位承受符号名,“=”后语句将相对值地址赋给变量名,这种地址分配有三种方法:方法1:sfr_name^int_constant当字节是特殊功能寄存器的地址可用这个方法.sfr_name必须是已定义的SFR的名字,“^”后的语句定义了基地址上的特殊位的位置,该位置必须是一个0~7的数.例: sfr PSW=0xD0;sfr LE=0xA8;sbit OV=PSW^2;sbit CY=PSW^7;方法2:int_constant^int_constant这种方法以一整常数作基地址,该值必须在0x80~0xFF之间,并能被8整除,确定位的位置方法同上.例: sbit OV=0xD0^2;sbit CV=0xD0^7;sbit EA=0xA8^7;方法3: int_constant这种方法是将位的相对地址赋给变量,地址必须位于0x80~0xFF之间.例: sbit OV=0xD2;sbit CY=0xD7;sbit EA=0xAF;特殊功能位代表了一个独立的声明类,它不克不及与其它声明和位域互换.1.3.4BIT:位标量声明除了通常的C数据类型外,C51编译器支持“bit”数据类型,对此有下列扩大与限制:(1)函数可包含类型为“bit”的参数,也可将其作为返回值.bit bfunc(bit b0,bit b1){/*……*/return(b1);}注:使用制止中断(#pragma disable)或包含明白的寄存器组切换(using n)的函数不克不及返回位值,在这种情况下,编译器会识别出来并发生一个错误信息.(2)位标量声明的语法及C声明的语义static bit dirction_bit;extern bit lock_printer_port;bit display_invers;(3)对于位声明的限制●位不克不及声明为一个指针(bit *bit_poiter)●不存在位数组(bit b_array[5])位声明中允许定义存贮器类型,位都被放入一个位段,它总是在8051外部RAM中,因此存贮器类型限制为DATA或IDATA,声明为其它存贮器类型都将导致编译出错.1.3.5可位寻址对象可位寻址对象指可以字节或位寻址的对象,当对象位于MSC-51可寻址RAM中时会有这种情况,C51允许带“bdata”类型的对象放入可位寻址存贮器中.bdata int ibase; /*位寻址指针 int*/bdata char bary[4]; /*位寻址数组 arrray*/使用“sbit”声明可独立访问可位寻址对象的位:sbit mybit0=ibase^0;sbit mybit15=ibase^15;sbit ary07=bary[0]^7;sbit ary37=bary[3]^7;对象“ibase”和“bary”也可位寻址:ary37=0;/*寻址“bary[3]”中的位7*/ibase=-1;/*寻址字节地址*/mybit15=0;/*寻址“ibase”的位15*/sbit声明要求基址对象的存贮器类型为“bdata”,否则只有相对的位声明方法是合法的.位位置(‘^’操纵符号后)的最大值依赖于指定的基类型,这个值于char/uchar而言是0~7,对于int/uint/short/ushort而言是0~15,对于long/ulong而言是0~31.在编译器内存贮器类型bdata与data一样操纵,而且只作与可再定位的sbit的运算.注:可位寻址的的段长最大不克不及超出16字节,可再定位的sbit声明自动转为公共的(PBULIC)以使它们能被其它C 模块使用.模块1:sbitary37=bary[3]^7;模块2:externbit ary37;sbit声明也可为布局和函数所用:unionlft{float mf;long ml;} ;bdatastructbad { char ml; union lft u; }tcp;sbit tcpf31=tcp.u.ml^31; /*浮点限制*/sbit tcpml0=tcp.ml^0;sbit tcmpl7=tcp.ml.^7;注:位位置的指定不克不及直接被float类型所用,如果需要这样做,浮点标量必须与一个长整型标量一起放入一个结合中而且位位置必须由长整型题目指定(见上例).1.4存贮器类型C51编译器完全支持8051微处理器及其系列的布局,可完全访问MCS-51硬件系统所有部分.每一个变量可准确地赋予分歧的存贮器类型(data,idata,pdata,xdata,code).访问外部数据存贮器(idata)要比访问外部数据存贮器(xdata)相对要快一些,因此,可将常常使用的变量置于外部数据存贮器中,而将较大及很少使用的数据单元置于外部数据存贮器中.data char charvar;char code msg[]=”ENTER PARAMETER:”;unsigned long xdata array[100];float idata x,y,z;unsigned char xdata vector[10][4][4];sfr p0=0x80;sbit RI=0x98;char bdata flags;sbit flago=flags^0;如果在变量说明时略去存贮器类型标记符,编译器会自动选择默许的存贮器类型.默许的存贮器类型进一步由节制指令SMALL、COMPACT 和LARGE限制.例如:如果声明char charvar,则默许的存贮器形式为SMALL,charvar放在data存贮器;如果使用COMPACT形式,则charvar放入idata存贮区;在使用LARGE形式的情况下,charvar被放入外部存贮区或xdata存贮区.1.5存贮器形式存贮器形式决议了自动变量和默许存贮器类型,参数传递区和无明白存贮区类型的说明.在固定的存贮器地址变量参数传递是C51的一个尺度特征,在SMALL形式下参数传递是在外部数据存贮区中完成的.LARGRE和COMPACT形式允许参数在外部存贮器中传递.C51同时也支持混合形式,例如在LARGE形式下生成的程序可将一些函数分页放入1.6指针Franklin C-51支持“基于存贮器的”和“一般指针”.1.6.1基于存贮器的指针基于存贮器的指针由C源代码中存贮器类型决议并在编译时确定,用这种指针可高效访问对象且只需一个字节(idata*,data*,pdata*)或2个字节(code*,xdata*).操纵较短指针的代码被缩短,一般被“行家”编码;库调用不再需要.上面例子说了然指针的一般声明及使用.它们与所有的数据类型和存贮器类型相关.所有用于一般指针的操纵同样可用于基于存贮器的指针.1.6.2一般指针“一般”指针需3个字节:1个字节为存贮类型,2个字节为偏移量.存贮器类型决议了对象所用的8051存贮器空间,偏移量指向实际地址.一个“一般”指针可访问任何变量而不管它在8051存贮器空间中的位置.这样就允许一般性函数,如memcpy将数据从任意一个地址拷贝到另外一个地址空间.1.6.3基于存贮器的指针与一般指针的转换一个已定位指针可转换为一个一般指针(3字节)及副本.这在某些时候是很有用的.例如库函数包含一个一般指针变量,象printf(),sprintf(),gets()等包含一个一般指针变量,如同以前的编译器和库版本一样.这些函数因而广泛适用.例:extern int printf(void *format,…);在printf调用中,2字节指针自动转换为一个3字节指针,而printf的原型正需要一个一般指针(3字节)作为其第一参量.注:如果没有函数原型,函数调用的参量中指针总是转换为一般指针.如果函数确实需要一个短指针作参量,这会发生错误,为了防止在程序中发生这类错误,需要使用头文件,或某些函数声明函数原型.这将包管让编译器转换为所需类型,否则会发生类型不匹配错误.1.6.4抽象指针类型抽象指针类型用来在每一个存贮区访问任意相对地址,或来发生相对CALLs.在这个过程中,常数类型或字符型、整型都用抽象类型作了原则性修改(类型整理)以允许停止相对访问或调用.例:char xdata *px;char idata *pi;char code *pc;char c;int i;pc = (void*)main;i = ((int(code*)(void))0xFF00(); /*LCALL 0FF00H*/c = *((char code*)0x8000); /*char [code[0x8000]]*/i = *((int code*)0x1200); /*int from code[0x1200]*/px = *((char xdata *xdata*)0x4000); /*x ptr from xdata[0x4000]*/px = ((char xdata *xdata*)0x4000)[0]; /*同上*/px = ((char xdata *xdata *)0x4000)[1] /*x ptr from xdata[0x4002]*/1.7寄存器组定义8051系列的器件包含4个相同的寄存器组,每一个寄存器组包含8个寄存器(R0~R7),C51编译器可以使在一函数中决议用哪一寄存器组成为可以.相对寄存器的访问可用AREGS/NOAREGS和REGISTERBANK 来节制.定义一个带扩大性的函数语法如下:返回类型函数名([参数])[形式][再入][中断 n]using n再入和中断将在后两节讨论.例:void rb_function(void) using 3;“using”不允许用于外部函数,它对函数的方针代码影响如下:●函数入口处将当前寄存器保管入栈;●指它的寄存器还会改变;●函数退出前寄存器组被恢复.“using”定义对于返回一个寄存器内的值的函数是无用的.编程者必须十分小心以包管任何寄存器切换都只在仔细节制的区域发生.如果不做到这一点将会发生不正确的函数成果.即使当编程者使用同一寄存器组时,带“using”属性的函数原则上也不克不及返回一个位值.实际发生的代码决议于编译器及分歧开关条件,有时用饬令发生相对的寄存器地址,当需要停止这样的地址计算时,使用REGISTERBANK 指令的影响只是计算Arn寄存器使用的地址,而必停止实际切换.1.8中断服务程序C51编译器及其对C语言的扩大允许编程者对中断的所有方面停止节制.这种支持能使系统编程者创建高效的中断服务程序,用户只需在普通和高级方式下关心中断及需要的寄存器组切换操纵,C51编译器将发生最合适的代码.1.8.1中断服务程序的定义使用中断服务函数的完整语法如下:返回值函数名([参数])[形式][再入] interrupt n[using n]“interrupt”后接一个0~31的常数,不允许使用表达式.中断不允许用于外部函数,它对函数方针代码的影响如下:●当使用函数时,SFR中的ACC、B、DPH、DPL和PSW(当需要时)入栈;●如不使用寄存器组切换,甚至中断函数所需的所有工作寄存器(Rn)都入栈;●函数退出前,所有的寄存器内容出栈;●函数由8051节制饬令“RETI”终止.1.8.2开辟中断过程时的规则●不克不及停止参数传递,如果中断过程包含任何参数声明,编译器将发生一个错误信息;●无返回值,如果想定义一个返回值将发生错误,然而,如果返回整型值编译器将不发生错误信息,因为整型值是默许值,因而编译器不克不及清楚识别.●编译器会识别对中断过程的直接调用并回绝它们,在任何情况下不克不及直接调用中断过程,因为退出该过程是由操纵码RETI完成的.RETI影响8051芯片的硬件中断系统,由于硬件上没有中断请求存在,因而这个操纵码的成果是不定的而且通常是致命的.由于疏忽,可以用指针来间接调用它,这是值得注意的.●编译器从相对地址8n+3处发生一个中断向量,其中n为中断号,该向量包含一个到中断过程的跳转,向量的发生可由指令NOINTVECTOR压缩.因而用户有才能从独立的汇编模块中提供中断向量.●C51编译器允许0~31个中断,毕竟允许哪些中断依赖于使用的8051系列芯片,编译器不克不及检查.●如果中断程序中有浮点运算,必须坚持浮点寄存器状态,当没有其它程序执行浮点运算时,可以不保管,函数“fsave”和“fprestore”用来保管浮点状态.●中断过程调用的函数所使用的寄存器必须与中断过程相同,当没有使用“using”指令时,编译器会选择一个寄存器组作相对寄存器访问,当子程序使用另外一个寄存器组时会发生错误,用户必须包管按要求使用相应寄存器组,C编译器不会对此检查.例:unsigned int interruptent;unsigned char second;time() interrupt 1 using 2/*定时器0中断服务程序,工作寄存器使用2区*/{if(++interruptcnt==4000) {second++;/*秒计数加一*/interruptcnt=0;/*清中断计数*/}}1.9再入函数再入函数可被递归调用,调用可发生在任何时候,即使是在中断过程中.在实时处理的应用问题中常常需要再入函数.使用关键字“reentrant”可有选择地定义函数有再入才能.在存贮器形式的基础上为再入函数在外部或外部存贮器中摹拟了一个栈区域.由于MCS-51缺乏合适的寻址方法,使用栈布局是相当需要的.因而应尽可以少用再入函数.定义一再入函数的语法如下:返回值函数名([参数])[形式]reetrant[interrupt n][using n] 例:int calc(char i,int b) reentrant {int x;x=table[i];return(x*b);}使用再入函数有如下规定:●不克不及传递类型为“bit”的参数.也不克不及声明一个部分标量,再入功能不克不及包含位操纵及MCS-51可位寻址区域.●不克不及在“alien”函数调用再入函数.●再入函数可同时有其它属性,如“using”函数形式和“interrupt”.●再入函数不克不及同时有“alien”属性,从而遵守PL/M规则.●返回地址及可以的PUSH/POP操纵存入MCS-51的栈中或被执行(不在再入栈中).●在同一模块中,任意模块的再入函数(small reentrant,lagereentrant,compact reentrant)不克不及与具有分歧形式的再入函数混合.再入函数举例:/*这个再入函数可以从“main”及中断程序中调用*/int calc(char i,int b)reentrant {int x;x=table[i];return(x*b);}1.10参数传递通过CPU的寄存器可传递至多三个参数.这样发生与汇编子程序相当的有效参数机制.如果寄存器被占用,或说了然“#pragma NOREGPARMS”,参数变量将使用固定的存贮器位置,存贮器形式决议了8051存贮器为参数提供的位置.表:候选的参数寄存器函数的返回值放在CPU固定的寄存器中,列表如下.这样,与汇编子程序的接口变得非常容易.1.11PL/M51接口Franklin C51操纵关键字“alien”提供了一个与Intel PL/M-51直接和简单和接口,关键字“alien”在所有存贮器形式下可用于“extern”和“public”函数.现有的PL/M-51程序操纵C语言的强大功能可与Franklin C-51毗连起来.使用关键字“alien”,C51可用PL/M-51规定的参数传递方式工作.“alien”可用于外部或公共函数,并可用于任一形式,这样,已有的PL/M-51程序可加入到C-51中.Alien函数始终包含一个尺度的参数数量,因此,C中定义的三点(…)记号不被承受,且会发生一个错误信息.例:extern alien char plm_function(unsigned char,unsigned int);extern char c_function(unsigned char x,unsigned char y) { return(x*y);}PL/M-51兼容函数必须定义以关键字“alien”.这样,PL/M函数的参数传递及参数返回规定在C编译器中才被思索.1.12汇编接口参数是通过固定的CPU寄存器传给汇编程序的,当使用“#pragma NOREGPARMS”时,则通过固定的存贮器位置传递参数.这样就给汇编与Franklin C-51之间提供了一个非常简洁的接口.返回值在CPU寄存器中.下例为在汇编中用来编码的“toupper”函数,参数传递发生在寄存器中.UPPERSEGMENTCODE;程序代码段PUBLIC_toupper;入口地址RESGUPPER;选择程序代码段toupper:MOVA,R7;char 参数在寄存器R7中CJNEA,#’a’,UPP1UPP1:JCUPPERTCJNEA,#’z’+1,UPP2UPP2:JNEUPPRETUPPRET:MOVR7,A;char 返回值在寄存器R7中RET;返回C1.13外部函数Franklin C-51支持下列外部函数.外部函数既是再入的又是有效的.表:C51的外部函数1.14Franklin C51可将即使有经历的程序员编制的代码停止优化.用户可选6个优化级,别的,用OPTIMIZE(SIZE),NOREGPARMS和NOAREGS时会影响生成代码的类型.C51的所有优化如下:(1)一般优化:●常数折迭:发生在一个表达式或地址计算中的几个常数值组合为一个常数.●跳转优化:跳转转到最终的方针地址,以提高程序效率.●死码消除:不成执行代码(死码)可从程序中去掉.●寄存器变量:只要有可以,自动变量和参量放入寄存器中,为这些变量保存的数据存贮器将去除.●通过寄存器传递参数:寄存器中可传递最多三个参数.●全局公共子式消除:相同的子表达式或地址计算(多次发生在同一函数中)将被识别出来,而且只要有可以,将只计算一次.(2)基于8051的优化:●窥孔(PEEPHOLE)优化:只要能节俭存贮空间或执行时间,复杂的运算都将化简.●访问优化:常数和变量直接包含在操纵中.●数据覆盖:函数的数据和位移被标识表记标帜为OVERLAYABLE,被L51用其它数据和位覆盖.●CASE/SWITCH优化:SWITCH/CASE语句优化为一个跳转或一串跳转.(3)代码生成选项:●OPTMIZE(SIZE):共同的“C”操纵被子程序代替:程序码长被压缩.●NOAREGS:不使用相对寄存器访问,程序代码在这种方式下独立于寄存器组.●NOREGPARMS:参数传递总是在本数据段完成,程序代码与早期C-51版本兼容.1.15C库C-51编译器包含6个分歧的编译库,可根据分歧函数的需要停止优化,这些库几乎支持所有的ANSI函数调用.因此,用此尺度的C程序可在编译和毗连后当即运行.C51修改.用户改变对于现有硬件输入和输出布局的两个模块,便可修改所有库函数,同样也可以重新很快地构造如“printf”和“puts”函数用LCD显示.L51毗连器的检查从而包管所有模块都用一种形式编译并自动选择编译库,从而使用户完全可以不必分歧库的细节.1.16配置文件C51编译器可根据分歧的硬件环境由4个文件作出修改.下列配置文件包含在C-51软件包中:所有的文件都包含在C运行库中,因此,不克不及在毗连时指定调用.如果用户改变一个文件,可将其编译后与其它方针文件一起毗连,因而不必改动运行库.库中原文件自动忽略.例:文件STARTUP.51开首包含一些C编译布局使用的EQU语句.每一个EQU语句的功能描绘如下:IDATALEN 声明系统开端时有多少内存需要用0初始化.默许值为80H,因为几乎每一个8051指令至少包含128字节外部RAM.对于256字节外部RAM的8052可以使用100H.当用户程序在开端时需要使用0初始化的内存时才有需要作改动.如果内存初始化必须坚持对掉电形式系统的完全抑制,IDATALEN应设为0.这种情况下至少得坚持所有位于段?C_LIB_DATA和?C_LIB_DBIT中的变量都置为0.否则有些库函数不克不及完全发挥作用,?C_LIB_DATA段的长度因分歧应用问题而分歧,其当前长度可在MAP文件中找到.XDATASTARTXDATALEN标了然需要以0初始化的PDATA区首址和长度,XDATASTART 指了然XDATA区首址,XDATALEN标了然需初始化的字节数.PDATASTARTPDATALEN标了然需以0初始化的PDATA区首址及长度,PDATASTART指了然首址,XDATALEN指定了长度.LBPSTACKLBPSTACKTOP 定义了SMALL形式下创建的再入函数使用的栈区.LBPSTACK标明是否对栈指针(变量?C_LBP)初始化,LBPSTACKTOP指了然栈顶首址.对于具有256字节外部RAM的8051系统,当存贮区作首址为0XFF的栈时,可不初始化.C51不作栈区是否知足特定应用的检查,用户必须自己停止测试. XBPSTACKXBPSTACKTOP 为在LARGE形式下创建的再入函数定义了栈区,XBPSTACK标明指针(变量?C_XBP)是否初始化,XBPSTACKTOP指定了栈顶地址.当存贮区作为首址为0Xffff(在XDATA区)的栈时,可不作初始化.同上一样,C51不作栈检查,需要用户自己测试.PBPSTACKPBPSTACKTOP 为在COMPACT形式下创建的再入函数定义了栈区,PBPSTACK标明栈指针(变量?C_PBP)是否初始化.PBPSTACKTOP指定了栈顶地址.当存贮区作为首址为0Xff(在PDATA区)的栈时,可不作初始化.同上一样,C51不作栈检查,需要用户自己测试.PPAGEENABLEPPAGE当在COMPACT形式中用16位寻址XDATA存贮区时需要这些指令.对于使用LARGE形式的程序,可用它提高运行速度或减小代码长度.PPAGEENABLE允许8051端口2的初始化,对端口2的寻址允许在任意XDATA页256字节变量空间的映射.这两个指令必须和L51的节制指令PDATA一起使用.PDATA指定了XDATA存贮器中PDATA区的首址.例:在STARTUP.A51中,PPAGEENABLE置为1,PPAGE置为10H.这种情况下PDATA区首址为1000H(10H页),而L51必须包含一个值在1000和10FFH之间的节制语句:L51〈输入模块〉PDATA(1050H).注:L51和C51都分歧错误PPAGE/PDATA指令阃确性停止检查,用户必须包管PPAGE和PDATA包含一个合适的值.INIT.A51:“看门狗”刷新的宏.当系统包含“看门狗”以及用户变量初始化时间比“看门狗”刷新时间要长时,必须改变这个宏.这种情况下,宏WATCHCOG必须包含“看门狗”刷新的代码.例:;Watchdog refresh for 80515 systemWATCHDOG MACROSETBWDTSETBSWDTENDM文件PUTCHAR.C包含字符输出的核心程序,该文件通过串行口输出.这种情况下思索了XON/XOFF协议,字符LF()被转为字符串CR,LF,这在很多终端中是需要的.用户可按自己的要求改变putchar()函数.文件GETKEY.C包含字符输入的核心程序,该文件从串行接口读入一个字符,不当准据转换,用户可根据需要修改getkey()函数.1.17优化程序本节包含几个怎样提高8051程序效率的注解.定位变量常常访问的数据对象应放入在片内数据RAM中,这可在任一形式(COMPACT/LARGE)下用输入存贮器类型的方法实现.访问片内数据RAM 要比访问外部数据存贮器快得多.片内RAM由寄存器组,位数据区栈和其它由用户用“data”类型定义的变量共享.由于片内RAM容量的限制(128~256字节,由使用的处理器决议),必须权衡利害以处理访问效率和这些对象的数量之间的抵触.总是使用可以的最小数据类型8051系列CPU都是8位机,因此,显然对具有“char”类型的对象的操纵比“int”或“long”类型的对象方便得多.建议编程者只要知足要求,应尽可以使用最小数据类型.C51编译器直接支持所有的字节操纵,因而如果不是运算符要求,就不作“int”类型的转换,这可用一个乘积运算来清楚说明,两个“char 类型”对象的乘积与8051操纵码“MUL AB”刚好相符.如果用整型量完成同样的运算,则需要调用库函数.只要有可以,使用“unsigned”数据类型8051系列CPU其实不直接支持有符号数的运算.因而C51编译器必须发生与之相关的更多的代码以处理这个问题.如果使用无符号类型,发生的代码要少得多.只要有可以,使用部分函数变量编译器总是测验测验在寄存器里坚持局中变量.这样,将索引变量(如FOR和WHILE循环中计数变量)声明为部分变量是最好的,这个优化步调只为部分变量执行.使用“unsigned char/int”的对象通常能获得最好的成果.2C51编译器节制指令编译选项可以被节制指令激活、制止或改变.这些指令可在饬令行输入或在源文件上加入#pragma给预处理器.节制指令分为两组,即首要。
单片机C51程序设计.ppt
单片机C51程序设计
C51对外部I/O的访问
假定LCD的端口地址为8000H~8003H则:
#include <absacc.h> // LCD Registers addresses #define LCD_CMD_WR XBYTE[8000] #define LCD_DATA_WR XBYTE[8001] #define LCD_BUSY_RD XBYTE[8002] #define LCD_DATA_RD XBYTE[8003]
数据的存储器模式
指针变量的说明
long xdata * px;
char xdata * data pd; // 指向xdata, 但指针在data
int * px; // 指向idata的整型变量的指针 unsigned int * px; // 指向idata的无符号整型变量的指针
单片机C51程序设计
#include <absacc.h> //LCD Registers addresses #define LCD_CMD_WR XBYTE[8000] #define LCD_DATA_WR XBYTE[8001] #define LCD_BUSY_RD XBYTE[8002] #define LCD_DATA_RD XBYTE[8003] (假定某LCD的端口地址为8000H~8003H)
单片机C51程序设计
主讲 聂雄
单片机C51程序设计
概述 C51程序结构 C51数据类型 数据的存储类型和存储器模式 C51对SFR、可寻址位、存储器和I/O口定义 C51运算符 函数 C语言编程实例 中断程序函数的格式
单片机C51程序设计
概述
C语言是一种通用的程序设计语言,其代码 效率高,数据类型及运算符丰富,并具有很 好看程序结构,适用于各种应用的程序设计。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第一节:吴坚鸿谈初学单片机的误区。
(1)很难记住繁杂的寄存器?寄存器不用死记硬背,鸿哥我行走江湖多年,连一个寄存器都记不住。
需要配置寄存器的时候,直接在网上或者书本上参考别人现成的配置程序是上策,查找芯片数据手册是中策,死记硬背寄存器是最最下策。
(2)很难记住繁杂的汇编语言指令?除非是在校学生要应付考试或者少数工作中绕不开汇编,否则学汇编就是浪费时间。
鸿哥我行走江湖多年,从来就没有用汇编帮客户做过一个项目。
(3)C语言很难学?你不用学指针,你不用学数组,你不用学带形参和实参的函数,你不用学结构体,你不用学宏定义,你不用学文件操作,你也不用死记繁琐的数据类型。
你只要会:5条指令语句switch语句,if else语句,while语句,for语句,=赋值语句。
4个运算符+-*/。
3个数据类型unsigned char, unsigned int, unsigned long。
3个进制相互转化,二进制,十六进制,十进制。
1个void函数。
那么世界上任何一种逻辑功能的单片机软件你都能做出来。
鸿哥我当年刚毕业出来工作的时候才知道可以用C语言开发单片机,一开始只用if语句就把项目做出来了,没有用指针,没有用数组,没有用带形参和实参的函数等复杂的功能。
再到后来才慢慢开始用C语言其他的高级功能,但是我发现C语言其他的高级功能,本质上都是用我前面列举出来的最基本功能集合而成,只是书写更加简单方便了一点,编译后的机器码都大同小异。
所以不会指针不会数组等高级功能你不用自卑,恰恰相反,当你会最简单的几个语句,就把这些高级功能的程序都做出来了,你才发现你对底层了解得更加透切,再学那些高级功能轻而易举。
当你裸机跑的程序都能够协调得很好的时候,你才发现所谓高深的操作系统也不过如此,只要给你时间和金钱你也可以写个操作系统来玩玩。
(4)很难记住精确时间的计算公式?经常看到时间公式等于晶振,时钟周期,执行指令次数他们之间的乘除关系式。
鸿哥我认为这些都是浮云,不用纠结也不用去记,大概了解一下就可以了。
不管你对公式掌握得有多精确,你都不可能做出非常精确的时间。
想用单片机做一个非常精确的时间这种想法一开始就是错的,不可能的。
真想做一个比较精确的时间,应该用外围时钟芯片或者FPGA和CPLD,而不是单片机。
(5)很难记住繁杂的各种通信协议?什么IIC,SPI,232串口通讯,CAN,USB等等。
这些都是浮云,你不用记那么多,你只要理解两种通讯方式就够了,那就是串行通讯方式和并行通讯方式。
不管世界上有多少种通讯协议,物理世界上只有这两种通讯方式,其他各种名称的通讯协议都基于此两种方式演变而来。
(6)很难写短小精悍的程序?初学者不要纠结于此。
做项目开发,程序容量不是刻意追求的目标,程序多一点少一点没关系,现在大容量的单片机品种非常多,容量不会是寸土寸金的事情,我们更加要关注程序的运行效率,可读性和可修改性。
(7)很难选出适合自己的51单片机学习板?市场上各种学习板子非常繁多,鸿哥认为最好的学习板是朱兆祺的51单片机学习板。
选它只有一个理由:有牛人提供后续一系列的视频和教学资料。
如果说鸿哥是牛人,那么朱兆祺就是天才。
我比朱兆祺大7岁,但是我现在完全拜倒在朱兆祺的牛仔裤下,成为他团队中的一员,听凭他调遣。
他确实有他过人之处,百年一遇的人才。
我这个连载的技术贴和以后的视频都是基于朱兆祺的51单片机学习板为硬件平台。
朱兆祺本人现在也正在捉紧时间录制视频,分享此学习板的资料。
既然鸿哥列出了那么多误区,那么什么才是初学者关注的核心?预知详情,请听下回分解----delay()延时实现LED灯的闪烁。
第二节:delay()延时实现LED灯的闪烁。
开场白:上一节鸿哥列出了初学者七大误区,到底什么才是初学者关注的核心?那就是裸机奔跑的程序结构。
一个好的程序结构,本身就是一个微型的多任务操作系统。
鸿哥教给大家的就是如何编写这个简单的操作系统。
其实这个结构非常简单,就是用switch语句实现多任务并行处理的状态机,鸿哥也称此状态机为单片机中的战斗机,它是鸿哥所有实战程序的核心。
大家不用着急,本篇连载文章现在才正式开始,这一节我要教会大家两个知识点:第一点:鸿哥首次提出的“三区一线”理论。
此理论把程序代码分成三个区,一个延时分割线。
第二点:delay()延时的用途。
(1)硬件平台:基于朱兆祺51单片机学习板。
(2)实现功能:让一个LED闪烁。
(3)源代码讲解如下:#include "REG52.H"void initial_myself();void initial_peripheral();void delay_short(unsigned int uiDelayshort);void delay_long(unsigned int uiDelaylong);void led_flicker();/* 注释一:* 吴坚鸿个人的命名风格:凡是输出后缀都是_dr,凡是输入后缀都是_sr。
* dr代表drive驱动,sr代表sensor感应器*/sbit led_dr=P3^5;void main() //学习要点:深刻理解鸿哥首次提出的三区一线理论{/* 注释二:* initial_myself()函数属于鸿哥三区一线理论的第一区,* 专门用来初始化单片机自己的寄存器以及个别外围要求响应速度快的输出设备,* 防止刚上电之后,由于输出IO口电平状态不确定而导致外围设备误动作,* 比如继电器的误动作等等。
*/initial_myself();/* 注释三:* 此处的delay_long()延时函数属于第一区与第二区的分割线,* 延时时间一般是0.3秒到2秒之间,等待外围芯片和模块上电稳定。
* 比如液晶模块,AT24C02存储芯片,DS1302时钟芯片,* 这类芯片有个特点,一般都是跟单片机进行串口或并口通讯的,* 并且不要求上电立即处理的。
*/delay_long(100);/* 注释四:* initial_peripheral()函数属于鸿哥三区一线理论的第二区,* 专门用来初始化不要求上电立即处理的外围芯片和模块.* 比如液晶模块,AT24C02存储芯片,DS1302时钟芯片。
* 本程序基于朱兆祺51单片机学习板。
*/initial_peripheral();/* 注释五:* while(1){}主函数循环区属于鸿哥三区一线理论的第三区,* 专门用来编写被循环扫描到的非中断应用程序*/while(1){led_flicker(); //LED闪烁应用程序}}void led_flicker() //LED闪烁应用程序{led_dr=1; //LED亮delay_short(50000); //延时50000个空指令的时间/* 注释六:* delay_long(100)延时50000个空指令的时间,因为内嵌了一个500次的for 循环*/led_dr=0; //LED灭delay_long(100); //延时50000个空指令的时间}/* 注释七:* delay_short(unsigned int uiDelayShort)是小延时函数,* 专门用在时序驱动的小延时,一般uiDelayShort的数值取10左右,* 最大一般也不超过100.本例为了解释此函数的特点,取值范围超过100。
* 此函数的特点是时间的细分度高,延时时间不宜过长。
uiDelayShort数值* 的大小就代表里面执行了多少条空指令的时间。
数值越大,延时越长。
* 时间精度不要刻意去计算,感觉差不多就行。
*/void delay_short(unsigned int uiDelayShort){unsigned int i;for(i=0;i<uiDelayShort;i++){; //一个分号相当于执行一条空语句}}/* 注释八:* delay_long(unsigned int uiDelayLong)是大延时函数,* 专门用在上电初始化的大延时,* 此函数的特点是能实现比较长时间的延时,细分度取决于内嵌for循环的次数,* uiDelayLong的数值的大小就代表里面执行了多少次500条空指令的时间。
* 数值越大,延时越长。
时间精度不要刻意去计算,感觉差不多就行。
*/void delay_long(unsigned int uiDelayLong)unsigned int i;unsigned int j;for(i=0;i<uiDelayLong;i++){for(j=0;j<500;j++) //内嵌循环的空指令数量{; //一个分号相当于执行一条空语句}}}void initial_myself() //初始化单片机{led_dr=0; //LED灭}void initial_peripheral() //初始化外围{; //本例为空}总结陈词:鸿哥首次提出的“三区一线”理论概况了各种项目程序的基本分区。
我后续的程序就按此分区编写。
Delay()函数的长延时适用在上电初始化。
Delay()函数的短延时适用在驱动时序的脉冲延时,此时的时间不能太长,本例中暂时没有列出这方面的例子,在后面的章节中会提到。
在本例源代码中,在led_flicker()闪烁应用程序里用到的两个延时delay,它们的延时时间都太长了,在实战项目中肯定不能用这种延时,因为消耗的时间太长了,其它任务根本没有机会执行。
那怎么办呢?我们应该如何改善?欲知详情,请听下回分解-----累计主循环次数使LED灯闪烁。
第四节:累计定时中断次数使LED灯闪烁。
开场白:上一节提到在累计主循环次数来实现计时,随着主函数里任务量的增加,为了保证延时时间的准确性,要不断修正设定上限阀值const_time_level 。
我们该怎么解决这个问题呢?本节教大家利用累计定时中断次数的方法来解决这个问题。
这一节要教会大家四个知识点:第一点:利用累计定时中断次数的方法实现时间延时第二点:展现鸿哥最完整的实战程序框架。
在主函数循环里用switch语句实现状态机的切换,在定时中断里累计中断次数,这两个的结合就是我写代码最本质的框架思想。
第三点:提醒大家C语言中的int ,long变量是由几个字节构成的数据,凡是在main函数和中断函数里有可能同时改变的变量,这个变量应该在主函数中被更改之前,先关闭相应的中断,更改完了此变量,再打开中断,否则会留下不宜察觉的漏洞。
当然在大部分的项目中可以不用这么操作,但是在一些要求非常高的项目中,有一些核心变量必须这么做。
第四点:定时中断的初始值该怎么设置。
不用严格按公式来计算时间,一般取个经验值是最大初始值减去1000就可以了。