单片机C语言小程序
单片机C语言小程序
#include
#include
#define V AR XBYTE[0x00] /*V AR为外部位址0000*/
#define read 0 /*93c46读取的识别码READ=0*/
#define write 2 /*93c46写入的识别码WRITE=2*/
#define ewen 4 /*93C46写致能的识别码EWEN=4*/
#define ewds 6 /*93C46写除能的识别码EWDS=6*/
#define cs INT0 /*93C46 CS接脚=8051 RD P3.2*/
#define clk INT1 /*93C46 CLK接脚=8051 WR P3.3*/
#define di T0 /*93C46 DI接脚=8051 T1 P3.4*/
#define d0 T1 /*93C46 DO接脚=8051 T0 P3.5*/
#define LOW 0x49 /*存放测试温度的下限值*/
#define HIGH 0x51 /*存放测试温度的上限值*/
bit FLAG0=0; /*宣告TIMER0响应旗号*/
//外接工业专用温度传感器时,目前设置测量温度为0-99度:
static const char tab[13]={0x3a,0x53,0x6f,0x8a,0xa3, /*0度,10度,20度,30度,40度*/
0xB8,0xC8,0xD5,0xDE,0xE5, /*50度,60度,70度,80度,90度*/
0xEA,0xEE}; /*100度,110度*/
//使用板上AD590温度传感器时,目前设置测量温度为0-99度:
//static const char tab[13]={0x88,0x8d,0x92,0x97,0x9c, /*0度,10度,20度,30度,40度,*/
// 0xa1,0xa6,0xab,0xb0,0xb5, /*50度,60度,70度,80度,90度*/
// 0xba,0xc0}; /*100度,110度*/
char data1[2];
char C,S,k=0;
char MEP[7]; /*显示器值存放阵列*/
//MEP[0]=数码管最低位显示值,温度指示小数点后位
//MEP[1]=数码管次低位显示值,温度指示个位数
//MEP[2]=数码管高位显示值,温度指示十位数
//MEP[3]=数码管最低位显示值,功能显示目前定为1,2,3,4,5
//MEP[4]=
//MEP[5]=暂放置温度显示值,高4位为温度指示十位数值,低4位为温度指示个位数值//MEP[6]=在温度显示与电压调整副程式中,将测量值C暂存MEP[6]中
unsigned char combuf[10];
unsigned char ADR46,CH,CL,m,C1,C2; /*ADR46,93C46位址,CH高位元组,CL低*/ int sec,sec1;
char ptr=0,ptr1=0x10,psr=0; /*ptr显示器值存放阵MEP[]指标,ptr1显示器扫描指标*/ char count=100,sb=0;
void delay (unsigned int value) /*延时副程式*/
{
while (value!=0) value--; /*10us延时*/
}
void COMP(); /*宣告比较现在温度与设定温度副程式*/
void SET();
void disp(); /*宣告设定温度副程式*/
void to9346(char c); /*宣告TO93C46副程式*/
void SDT46(char c); /*宣告串入副程式*/
RDT46(); /*宣告串出副程式*/
void clear(void); /*宣告清除按键存放/显示器阵列MEP[]副副程式*/
void xch(void); /*宣告按键存放/显示器阵列MEP[]右键滚入副程式*/
void sjust(void); /*温度显示慢跳调整副程式*/
void temper(); /*宣告温度显示与电压调整副程式*/
void UP(); /*宣告温度上升键防抖动副程式*/
void UPA(); /*宣告温度设置上升副程式*/
void DOWN(); /*宣告温度下降键防抖动副程式*/
void DOWNA(); /*宣告温度设置下降副程式*/
void FONTION(); /*宣告模式键判断模式副程式*/
void buf(); /*宣告从93C46取设定值副程式*/
void SA VE(); /*宣告设置存储副程式*/
//********************************************************
main() /*主程式*/
{
TMOD=0x11; /*TIMER0,TIMER1工作在MODE1*/
TH0=(65535-50000)/256; /*设定TIMER0初值,50ms*/
TL0=(65536-50000)%256;
TH1=(65535-4000)/256; /*设定TIMER1初值,4ms*/
TL1=(65536-4000)%256;
IE=0x8a; /*TIMER0,TIMER1中断致能*/
TR1=1; /*启动TIMER1*/
P2_7=1; /*测试用,温度下限指示*/
P2_6=1; /*测试用,温度在正常上下限间指示*/
P2_5=1; /*测试用,温度上限指示*/
buf(); /*从93C46取设定值副程式*/
while(1) /*无条件循环*/
{
P3_1=0;
MEP[3]=0xff; /*将模式位置零*/
V AR=0x00; /*产生写入信号WR=0,令ADC0804开始转换*/
while (P2_0==1); /*侦测ADC0804的接脚INTR=0否?是则转换完成*/
S=V AR; /*读取ADC0804资料,存入C*/
sjust(); /*温度显示慢跳调整副程式*/
temper(); /*呼叫温度显示调整副程式*/
MEP[5]=(MEP[2] < <4)|MEP[1];
if(P2_4==0) SET(); /*如果模式键P2.4按下,则呼叫SET副程式,否则跳过副程式*/
if(MEP[5] P2_6=P2_5=1; /*关闭指示灯*/ } if(MEP[5]> combuf[6]) { P2_5=0; /*如果测试温度大于设定温度上限,等式成立时,则将高温指示打开P2_5=0*/ P2_7=P2_6=1; /*关闭指示灯*/ } if(combuf[5] if(MEP[5] } } /*跳至while(1),无条件循环*/ 单片机的C语言轻松入门 随着单片机开发技术的不断发展,目前已有越来越多的人从普遍使用汇编语言到逐渐使 用高级语言开发,其中主要是以C语言为主,市场上几种常见的单片机均有其C语言开发 环境.这里以最为流行的80C51单片机为例来学习单片机的C语言编程技术. 本书共分六章,每章一个专题,以一些待完成的任务为中心,围绕该任务介绍C语言 的一些知识,每一个任务都是可以独立完成的,每完成一个任务,都能掌握一定的知识,等 到所有的任务都完成后,即可以完成C语言的入门工作. 第1章C语言概述及其开发环境的建立 学习一种编程语言,最重要的是建立一个练习环境,边学边练才能学好.Keil软件是目 前最流行开发80C51系列单片机的软件,Keil提供了包括C编译器,宏汇编,连接器,库 管理和一个功能强大的仿真调试器等在内的完整开发方案,通过一个集成开发环境 ( Vision)将这些部份组合在一起. 在学会使用汇编语言后,学习C语言编程是一件比较容易的事,我们将通过一系列的 实例介绍C语言编程的方法.图1-1所示电路图使用89S52单片机作为主芯片,这种单片 机性属于80C51系列,其内部有8K的FLASH ROM,可以反复擦写,并有ISP功能,支 持在线下载,非常适于做实验.89S52的P1引脚上接8个发光二极管,P3.2~P3.4引脚上接 4个按钮开关,我们的任务是让接在P1引脚上的发光二极管按要求发光. 1.1 简单的C程序介绍 例1-1: 让接在P1.0引脚上的LED发光. /************************************************* 平凡单片机工作室 https://www.360docs.net/doc/3d16494387.html, Copyright 2003 pingfan's mcustudio All rights Reserved 作者:周坚 dddl.c 单灯点亮程序 *************************************************/ 图1-1 接有LED的单片机基本电路 P1.0 EA/VPP VCC XTAL2 XTAL1 GND RST +5V+5V + R1E1 10K 10U CY27P 27P 1KPZ1 D8D1 89××× #include "reg51.h" sbit P1_0=P1^0; void main() { P1_1=0; } 这个程序的作用是让接在P1.0引脚上的LED点亮.下面来分析一下这个C语言程序包 含了哪些信息. 1)"文件包含"处理. 程序的第一行是一个"文件包含"处理. 所谓"文件包含"是指一个文件将另外一个文件的内容全部包含进来,所以这里的程序 虽然只有4行,但C编译器在处理的时候却要处理几十或几百行.这里程序中包含REG51.h 文件的目的是为了要使用P1这个符号,即通知C编译器,程序中所写的P1是指80C51单片机的P1端口而不是其它变量.这是如何做到的呢 打开reg51.h可以看到这样的一些内容: /*------------------------------------------------------------------------- REG51.H Header file for generic 80C51 and 80C31 microcontroller. Copyright (c) 1988-2001 Keil Elektronik GmbH and Keil Software, Inc. All rights reserved. --------------------------------------------------------------------------*/ /* BYTE Register */ sfr P0 = 0x80; sfr P1 = 0x90; sfr P2 = 0xA0; sfr P3 = 0xB0; sfr PSW = 0xD0; sfr ACC = 0xE0; sfr B = 0xF0; sfr SP = 0x81; sfr DPL = 0x82; sfr DPH = 0x83; sfr PCON = 0x87; sfr TCON = 0x88; sfr TMOD = 0x89; sfr TL0 = 0x8A; sfr TL1 = 0x8B; sfr TH0 = 0x8C; sfr TH1 = 0x8D; sfr IE = 0xA8; sfr IP = 0xB8; sfr SCON = 0x98; sfr SBUF = 0x99; /* BIT Register */ /* PSW */ sbit CY = 0xD7; sbit AC = 0xD6; sbit F0 = 0xD5; sbit RS1 = 0xD4; sbit RS0 = 0xD3; sbit OV = 0xD2; sbit P = 0xD0; /* TCON */ sbit TF1 = 0x8F; sbit TR1 = 0x8E; sbit TF0 = 0x8D; sbit TR0 = 0x8C; sbit IE1 = 0x8B; sbit IT1 = 0x8A; sbit IE0 = 0x89; sbit IT0 = 0x88; /* IE */ sbit EA = 0xAF; sbit ES = 0xAC; sbit ET1 = 0xAB; sbit EX1 = 0xAA; sbit ET0 = 0xA9; sbit EX0 = 0xA8; /* IP */ sbit PS = 0xBC; sbit PT1 = 0xBB; sbit PX1 = 0xBA; sbit PT0 = 0xB9; sbit PX0 = 0xB8; /* P3 */ sbit RD = 0xB7; sbit WR = 0xB6; sbit T1 = 0xB5; sbit T0 = 0xB4; sbit INT1 = 0xB3; sbit INT0 = 0xB2; sbit TXD = 0xB1; sbit RXD = 0xB0; /* SCON */ sbit SM0 = 0x9F; sbit SM1 = 0x9E; sbit SM2 = 0x9D; sbit REN = 0x9C; sbit TB8 = 0x9B; sbit RB8 = 0x9A; sbit TI = 0x99; sbit RI = 0x98; 熟悉80C51内部结构的读者不难看出,这里都是一些符号的定义,即规定符号名与地 址的对应关系.注意其中有 sfr P1 = 0x90; 这样的一行(上文中用黑体表示),即定义P1与地址0x90对应,P1口的地址就是0x90 (0x90是C语言中十六进制数的写法,相当于汇编语言中写90H). 从这里还可以看到一个频繁出现的词:sfr sfr并标准C语言的关键字,而是Keil为能直接访问80C51中的SFR而提供了一个新的关键词,其用法是: sfrt 变量名=地址值. 2)符号P1_0来表示P1.0引脚. 在C语言里,如果直接写P1.0,C编译器并不能识别,而且P1.0也不是一个合法的C 语言变量名,所以得给它另起一个名字,这里起的名为P1_0,可是P1_0是不是就是P1.0 呢你这么认为,C编译器可不这么认为,所以必须给它们建立联系,这里使用了Keil C 的关键字sbit来定义,sbit的用法有三种: 第一种方法:sbit 位变量名=地址值 第二种方法:sbit 位变量名=SFR名称^变量位地址值 第三种方法:sbit 位变量名=SFR地址值^变量位地址值 如定义PSW中的OV可以用以下三种方法: sbit OV=0xd2 (1)说明:0xd2是OV的位地址值 sbit OV=PSW^2 (2)说明:其中PSW必须先用sfr定义好 sbit OV=0xD0^2 (3)说明:0xD0就是PSW的地址值 因此这里用sfr P1_0=P1^0;就是定义用符号P1_0来表示P1.0引脚,如果你愿意也可以起P10一类的名字,只要下面程序中也随之更改就行了. 3)main称为"主函数". 每一个C语言程序有且只有一个主函数,函数后面一定有一对大括号"{}",在大括号 里面书写其它程序. 从上面的分析我们了解了部分C语言的特性,下面再看一个稍复杂一点的例子. 例1-2 让接在P1.0引脚上的LED闪烁发光 /************************************************* 平凡单片机工作室 https://www.360docs.net/doc/3d16494387.html, Copyright 2003 pingfan's mcustudio All rights Reserved 作者:周坚 ddss.c 单灯闪烁程序 *************************************************/ #include "reg51.h" #define uchar unsigned char #define uint unsigned int sbit P10=P1^0; /*延时程序 由Delay参数确定延迟时间 */ void mDelay(unsigned int Delay) { unsigned int i; for(;Delay>0;Delay--) { for(i=0;iNew Project…"菜单,出现对话框,要求给将要建立的工程起一个名字, 这里起名为exam2,不需要输入扩展名.点击"保存"按钮,出现第二个对话框,如图1-2 所示,这个对话框要求选择目标CPU(即你所用芯片的型号),Keil支持的CPU很多,这 里选择Atmel公司的89S52芯片.点击AT M E L前面的"+"号,展开该层,点击其中的89S52, 然后再点击"确定"按钮,回到主窗口,此时,在工程窗口的文件页中,出现了"Target 1", 前面有"+"号,点击"+"号展开,可以看到下一层的"Source Group1",这时的工程还是 一个空的工程,里面什么文件也没有,需要手动把刚才编写好的源程序加入,点击"Source Group1"使其反白显示,然后,点击鼠标右键,出现一个下拉菜单,如图1-3所示,选中其 中的"Add file to Group"Source Group1",出现一个对话框,要求寻找源文件. 双击exam2.c文件,将文件加入项目,注意,在文件加入项目后,该对话框并不消失, 等待继续加入其它文件,但初学时常会误认为操作没有成功而再次双击同一文件,这时会出现如图1-4所示的对话框,提示你所选文件已在列表中,此时应点击"确定",返回前一对 话框,然后点击"Close"即可返回主接口,返回后,点击"Source Group 1"前的加号,exam3.c 文件已在其中.双击文件名,即打开该源程序. 1.3 工程的详细设置 工程建立好以后,还要对工程进行进一步的设置,以满足要求. 首先点击左边Project窗口的Target 1,然后使用菜单"Project->Option for target 'target1'" 即出现对工程设置的对话框,这个对话框共有8个页面,大部份设置项取默认值就行了. Target页 图1-2 选择单片机型号 图1-3 加入文件 如图1-5所示,Xtal后面的数值是晶振频率值,默认值是所选目标CPU的最高可用频 率值,该值与最终产生的目标代码无关,仅用于软件模拟调试时显示程序执行时间.正确设 置该数值可使显示时间与实际所用时间一致,一般将其设置成与你的硬件所用晶振频率相同,如果没必要了解程序执行的时间,也可以不设. Memory Model用于设置RAM使用情况,有三个选择项: Small: 所有变量都在单片机的内部RAM中; Compact:可以使用一页(256字节)外部扩展RAM; Larget: 可以使用全部外部的扩展RAM. Code Model用于设置ROM空间的使用,同样也有三个选择项: Small:只用低于2K的程序空间; Compact:单个函数的代码量不能超过2K,整个程序可以使用64K程序空间; Larget:可用全部64K空间; 这些选择项必须根据所用硬件来决定,由于本例是单片应用,所以均不重新选择,按默 认值设置. Operating:选择是否使用操作系统,可以选择Keil提供了两种操作系统:Rtx tiny和 Rtx full,也可以不用操作系统(None),这里使用默认项None,即不用操作系统. 图1-5 设置目标 图1-4 重复加入源程序得到的提示 OutPut页 如图1-6所示,这里面也有多个选择项,其中Creat Hex file用于生成可执行代码文件, 该文件可以用编程器写入单片机芯片,其格式为intelHEX格式,文件的扩展名为.HEX,默 认情况下该项未被选中,如果要写片做硬件实验,就必须选中该项. 工程设置对话框中的其它各页面与C51编译选项,A51的汇编选项,BL51连接器的连 接选项等用法有关,这里均取默认值,不作任何修改.以下仅对一些有关页面中常用的选项作一个简单介绍. Listing页 该页用于调整生成的列表文件选项.在汇编或编译完成后将产生(*.lst)的列表文件, 在连接完成后也将产生(*.m51)的列表文件,该页用于对列表文件的内容和形式进行细致 的调节,其中比较常用的选项是"C Compile Listing"下的"Assamble Code"项,选中该项 可以在列表文件中生成C语言源程序所对应的汇编代码,建议会使用汇编语言的C初学者选中该项,在编译完成后多观察相应的List文件,查看C源代码与对应汇编代码,对于提 高C语言编程能力大有好处. C51页 该页用于对Keil的C51编译器的编译过程进行控制,其中比较常用的是"Code Optimization"组,如图1.7所示,该组中Level是优化等级,C51在对源程序进行编译时, 可以对代码多至9级优化,默认使用第8级,一般不必修改,如果在编译中出现一些问题, 可以降低优化级别试一试.Emphasis是选择编译优先方式,第一项是代码量优化(最终生 成的代码量小);第二项是速度优先(最终生成的代码速度快);第三项是缺省.默认采用速 度优先,可根据需要更改. 图1-6 设置输出文件 Debug页 该页用于设置调试器,Keil提供了仿真器和一些硬件调试方法,如果没有相应的硬件调 试器,应选择Use Simulator,其余设置一般不必更改,有关该页的详细情况将在程序调试部分再详细介绍. 至此,设置完成,下面介绍如何编译,连接程序以获得目标代码,以及如何进行程序的 调试工作. 1.4 编译,连接 下面我们通过一个例子来介绍C程序编译,连接的过程.这个例子使P1口所接LED 以流水灯状态显示. 将下面的源程序输入,命名为exam3.c,并建立名为exam3的工程文件,将exam3.c文 件加入该工程中,设置工程,在Target页将Xtal后的值由24.0改为12.0,以便后面调试时 观察延时时间是否正确,本项目中还要用到我们所提供的实验仿真板,为此需在Debug页 对Dialog DLL对话框作一个设置,在进行项目设置时点击Debug,打开Debug页,可以看 到Dialog DLL对话框后的Parmeter:输入框中已有默认值-pAT52,在其后键入空格后再输入-dledkey,如图1-8所示. 例1-3 使P1口所接LED以流水灯状态显示 /************************************************** ; 平凡单片机工作室 ; https://www.360docs.net/doc/3d16494387.html, ; Copyright 2003 pingfan's McuStudio ; All rights Reserved 图1-7C51编译器选项 ;作者:周坚 ;lsd.c ;流水灯程序 **************************************************/ #include "reg51.h" #include "intrins.h" #define uchar unsigned char #define uint unsigned int /*延时程序 由Delay参数确定延迟时间 */ void mDelay(unsigned int Delay) { unsigned int i; for(;Delay>0;Delay--) { for(i=0;iBuild target,对当前工程进行 连接,如果当前文件已修改,将先对该文件进行编译,然后再连接以产生目标代码;如果选 择Rebuild All target files将会对当前工程中的所有文件重新进行编译然后再连接,确保最终生产的目标代码是最新的,而Translate ….项则仅对当前文件进行编译,不进行连接.以上 操作也可以通过工具栏按钮直接进行.图1-9是有关编译,设置的工具栏按钮,从左到右分 别是:编译,编译连接,全部重建,停止编译和对工程进行设置. 编译过程中的信息将出现在输出窗口中的Build页中,如果源程序中有语法错误,会有 错误报告出现,双击该行,可以定位到出错的位置,对源程序修改之后再次编译,最终要得 到如图1-10所示的结果,提示获得了名为exam3.hex的文件,该文件即可被编程器读入并 写到芯片中,同时还可看到,该程序的代码量(code=63),内部RAM的使用量(data=9), 外部RAM的使用量(xdata=0)等一些信息.除此之外,编译,连接还产生了一些其它相关 的文件,可被用于Keil的仿真与调试,到了这一步后即进行调试. 1.5 程序的调试 在对工程成功地进行汇编,连接以后,按Ctrl+F5或者使用菜单Debug->Start/Stop Debug Session即可进入调试状态,Keil内建了一个仿真CPU用来模拟执行程序,该仿真CPU功 能强大,可以在没有硬件和仿真机的情况下进行程序的调试. 进入调试状态后,Debug菜单项中原来不能用的命令现在已可以使用了,多出一个用于 运行和调试的工具条,如图1-11所示,Debug菜单上的大部份命令可以在此找到对应的快 捷按钮,从左到右依次是复位,运行,暂停,单步,过程单步,执行完当前子程序,运行到 当前行,下一状态,打开跟踪,观察跟踪,反汇编窗口,观察窗口,代码作用范围分析,1 #串行窗口,内存窗口,性能分析,工具按钮等命令. 点击菜单Peripherals,即会多出一项"键盘LED仿真板(K)",选中该项,即会出现如 图1-9 有关编译,连接,项目设置的工具条 图1-11 调试工具条 图1-10 编译,连接后得到目标代码 图1-12所示界面. 使用菜单STEP或相应的命令按钮或使用快捷键F11可以单步执行程序,使用菜单STEP OVER或功能键F10可以以过程单步形式执行命令,所谓过程单步,是指把C语言中的一个函数作为一条语句来全速执行. 按下F11键,可以看到源程序窗口的左边出现了一个黄色调试箭头,指向源程序的第一行.每按一次F11,即执行该箭头所指程序行,然后箭头指向下一行,当箭头指向 "mDelay(1000);"行时,再次按下F11,会发现,箭头指向了延时子程序mDelay的第一行. 不断按F11键,即可逐步执行延时子程序. 如果mDelay程序有错误,可以通过单步执行来查找错误,但是如果mDelay程序已正 确,每次进行程序调试都要反复执行这些程序行,会使得调试效率很低,为此可以在调试时使用F10来替代F11,在main函数中执行到mDelay(1000)时将该行作为一条语句快速执行完毕. Keil软件还提供了一些窗口,用以观察一些系统中重要的寄存器或变量的值,这也是很 重要的调试方法. 以下通过一个对延时程序的延迟时间的调整来对这些调试方法作一个简单的介绍. 这个程序中用到了延时程序mDelay,如果使用汇编语言编程,每段程序的延迟时间可 以非常精确地计算出来,而使用C语言编程,就没有办法事先计算了.为此,可以使用观 察程序执行时间的方法了来解.进入调试状态后,窗口左侧是寄存器和一些重要的系统变量的窗口,其中有一项是sec,即统计从开始执行到目前为止用去的时间.按F10,以过程单 步的形式执行程序,在执行到mDelay(1000)这一行之前停下,查看sec的值(把鼠标停在sec 后的数值上即可看到完整的数值),记下该数值,然后按下F10,执行完mDelay(1000)后再 次观察sec值,如图1-13所示,这里前后两次观察到的值分别是:0.00040400和1.01442600, 其差值为1.014022s,如果将该值改为124可获得更接近于1s的数值,而当该值取123时所获得的延时值将小于1s,因此,最佳的取值应该是124. 图1-12 51单片机实验仿真板 1.6 C语言的一些特点 通过上述的几个例子,可以得出一些结论: 1,C程序是由函数构成的,一个C源程序至少包括一个函数,一个C源程序有且只有 一个名为main()的函数,也可能包含其它函数,因此,函数是C程序的基本单位.主程序 通过直接书写语句和调用其它函数来实现有关功能,这些其它函数可以是由C语言本身提供给我们的(如例3中的_crol_(…)函数),这样的函数称之为库函数,也可以是用户自 己编写的(如例2,3中用的mDelay(…)函数),这样的函数称之为用户自定义函数.那 么库函数和用户自定义函数有什么区别呢简单地说,任何使用Keil C语言的人,都可以 直接调用C的库函数而不需要为这个函数写任何代码,只需要包含具有该函数说明的相应的头文件即可;而自定义函数则是完全个性化的,是用户根据自己需要而编写的.Keil C提供了100多个库函数供我们直接使用. 2,一个函数由两部份组成: (1)函数的首部,即函数的第一行.包括函数名,函数类型,函数属性,函数参数(形 参)名,参数类型. 例如:void mDelay (unsigned int DelayTime) 一个函数名后面必须跟一对圆括号,即便没有任何参数也是如此. (2)函数体,即函数首部下面的大括号"{}"内的部份.如果一个函数内有多个大括 号,则最外层的一对"{}"为函数体的范围. 函数体一般包括: 声明部份:在这部份中定义所用到的变量,例1.2中unsigned char j. 执行部份:由若干个语句组成. 在某此情况下也可以没有声明部份,甚至即没有声明部份,也没有执行部份,如: void mDelay() {} 这是一个空函数,什么也不干,但它是合法的. 在编写程序时,可以利用空函数,比如主程序需要调用一个延时函数,可具体延时多少, 怎么个延时法,暂时还不清楚,我们可以主程序的框架结构弄清,先编译通过,把架子搭起 来再说,至于里面的细节,可以在以后慢慢地填,这时利用空函数,先写这么一个函数,这 样在主程序中就可以调用它了. 3,一个C语言程序,总是从main函数开始执行的,而不管物理位置上这个main()放 在什么地方.例1.2中就是放在了最后,事实上这往往是最常用的一种方式. 图1-13 观察sec确定延时时间 4,主程序中的mDelay如果写成mdelay就会编译出错,即C语言区分大小写,这一点 往往让初学者非常困惑,尤其是学过一门其它语言的人,有人喜欢,有人不喜欢,但不管怎样,你得遵守这一规定. 5,C语言书写的格式自由,可以在一行写多个语句,也可以把一个语句写在多行.没 有行号(但可以有标号),书写的缩进没有要求.但是建议读者自己按一定的规范来写,可 以给自己带来方便. 6,每个语句和资料定义的最后必须有一个分号,分号是C语句的必要组成部份. 7,可以用/*…..*/的形式为C程序的任何一部份作注释,在"/*"开始后,一直到"*/" 为止的中间的任何内容都被认为是注释,所以在书写特别是修改源程序时特别要注意,有时无意之中删掉一个"*/",结果,从这里开始一直要遇到下一个"*/"中的全部内容都被认 为是注释了.原本好好的一个程序,编译已过通过了,稍作修改,一下出现了几十甚至上百 个错误,初学C的人往往对此深感头痛,这时就要检查一下,是不是有这样的情况,如果 有的话,赶紧把这个"*/"补上. 特别地,Keil C也支持C++风格的注释,就是用"//"引导的后面的语句是注释,例: P1_0=!P1_0; //取反P1.0 这种风格的注释,只对本行有效,所以不会出现上面的问题,而且书写比较方便,所以 在只需要一行注释的时候,我们往往采用这种格式.但要注意,只有Keil C支持这种格式, 早期的Franklin C以及PC机上用的TC都不支持这种格式的注释,用上这种注释,编译时通不过,会报告编译错误. 第2章分支程序设计 第一部分课程学习了如何建立Keil C的编程环境,并了解了一些C语言的基础知识, 这一部分将通过一个键控流水灯程序的分析来学习分支程序设计. 2.1 程序功能与实现 硬件电路描述如下:89S52单片机的P1口接有8个LED,当某一端口输出为"0"时, 相应的LED点亮,P3.2,P3.3,P3.4,P3.5分别接有四个按钮K1~K4,按下按钮时,相应 引脚被接地.现要求编写可键控的流水灯程序,当K1按下时,开始流动,K2按下时停止 流动,全部灯灭,K3使灯由上往下流动,K4使灯由下往上流动. 下面首先给出程序,然后再进行分析. 例2-1:键控流水灯的程序 #include "reg51.h" #include "intrins.h" #define uchar unsigned char void mDelay(unsigned int DelayTime) { unsigned int j=0; for(;DelayTime>0;DelayTime--) { for(j=0;j2的结果为真,而3<2的结果为 假. C语言一共提供了6种关系运算符:"<"(小于),""(大于), ">=(大于等于)","=="(等于)和"!="(不等于). 用关系运算符将两个表达式连接起来的式子,称为关系表达式.例: a>b,a+b>b+c,(a=3)>=(b=5)等都是合法的关系表达式.关系表达式的值只有两种 可能,即"真"和"假".在C语言中,没有专门的逻辑型变量,如果运算的结果是"真", 用数值"1"表示,而运算的结果是"假"则用数值"0"表示. 如式子:x1=3>2的结果是x1等于1,原因是3>2的结果是"真",即其结果为1,该结 果被"="号赋给了x1,这里须注意,"="不是等于之意(C语言中等于用"=="表示), 而是赋值号,即将该号后面的值赋给该号前面的变量,所以最终结果是x1等于1. 式子:x2=30;DelayTime--) 单片机的C语言轻松入门 25 { for(j=0;j<125;j++) {;} } } 在main函数中用mDelay(1000)的形式调用该函数时,延时时间约为1s.如果将该函数 中的unsigned int j改为unsigned char j,其他任何地方都不作更改,重新编译,连接 后,可以发现延迟时间变为约0.38s.int和char是C语言中的两种不同的数据类型,可见 程序中仅改变数据类型就会得到不同的结果.那么int和char型的数据究竟有什么区别呢3.3.1 整型数据 1.整型数据在内存中的存放形式 如果定义了一个int型变量i: int i=10; /*定义i为整型变量,并将10赋给该变量*/ 在Keil C中规定使用二个字节表示int型数据,因此,变量i在内存中的实际占用情况 如下: 0000,0000,0000,1010 也就是整型数据总是用2个字节存放,不足部分用0补齐. 事实上,数据是以补码的形式存在的.一个正数的补码和其原码的形式是相同的.如果 数值是负的,补码的形式就不一样了.求负数的补码的方法是:将该数的绝对值的二进制形式取反加1.例如,-10,第一步取-10的绝对值10,其二进制编码是1010,由于是整型数占 2个字节(16位),所以其二进制形式实为0000,0000,0000,1010,取反,即变为1111, 1111,1111,0101,然后再加1变成了1111,1111,1111,0110,这个就是数-10在内存中 的存放形式.这里其实只要搞清一点,就是必须补足16位,其它的都不难理解. 2.整型变量的分类 整型变量的基本类型是int,可以加上有关数值范围的修饰符.这些修饰符分两类,一 类是short和long,另一类是unsigned,这两类可以同时使用.下面就来看有关这些修饰符 的内容. 在int前加上short或long是表示数的大小的,对于keil C来说,加short和不加short 是一模一样的(在有一些C语言编译系统中是不一样的),所以,short就不加讨论了.如果 在int前加上long的修饰符,那么这个数就被称之为长整数,在keil C中,长整数要用4个 字节来存放(基本的int型是2个字节).显然,长整数所能表达的范围比整数要大,一个 长整数表达的范围可以有: -231 { for(j=0;j0;DelayTime--) { for(j=0;j0;DelayTime--) { for(j=0;j<125;j++) 单片机的C语言轻松入门 31 {;} } } void main() { unsigned char OutData=0xfe; while(1) { P3|=0x3c; do { P1=OutData; OutData=_crol_(OutData,1); //循环左移 mDelay(1000); /*延时1000毫秒*/ } while((P3|0xfb)!=0xff) P1=0xff; } } 程序分析:这个程序除主程序中将while用do-while替代外,没有其他的变化,初步设 想,如果while()括号中的表达式为"真"即K1键被按下,应该执行程序体,否则不执 行,效果与例4-2相同.但是事实上,实际做这个练习就会发现,不论K1是否被按下,流 水灯都在工作.为何会有这么样的结果呢 单步运行程序可以发现,如果K1键被按下,的确是在执行循环体内的程序,与设想相 同.而当K1没有被按下时,按设想,循环体内的程序不应该被执行,但事实上,do后面的 语句至少要被执行一次才去判断条件是否成立,所以程序依然会去执行do后的循环体部分, 只是在判断条件不成立(K1没有被按下)后,转去执行P1=0xff;然后又继续循环,而下一 次循环中又会先执行一次循环体部分,因此,K1是否被按下的区别仅在于"P1=0xff;"这一 程序行是否会被执行到. 4.4 for语句 C语言中的for语句使用最为灵活,不仅可以用于循环次数已经确定的情况,而且可以用于循环次数不确定而只给出循环结束条件的情况. for语句的一般形式为: for(表达式1;表达式2;表达式3) 语句 它的执行过程是: (1) 先求解表达式1 (2) 求解表达式2,其值为真,则执行for语句中指定的内嵌语句(循环体),然后执行 第(3)步,如果为假,则结束循环. (3) 求解表达式3 (4) 转回上面的第(2)步继续执行. for语句典型的应用是这样一种形式: for(循环变量初值;循环条件;循环变量增值) 语句 例如上述例子中的延时程序有这样的程序行:"for(j=0;j=125)为止. 如果用while语句来改写,应该这么写 j=0; while(j0;DelayTime--){…}"的写法,省略掉了表达式1, 因为这里的变量DelayTime是由参数传入的一个值,不能在这个式子里赋初值. 表达式2也可以省略,但是同样不能省略其后的分号,如果省略该式,将不判断循环条件,循环无终止地进行下去,也就是认为表达式始终为真. 表达式3也可以省略,但此时编程者应该另外设法保证循环能正常结束. 表达式1,2和3都可以省略,即形成如for(;;)的形式,它的作用相当于是while(1),即 构一个无限循环的过程. 循环可以嵌套,如上述延时程序中就是两个for语句嵌套使用构成二重循环,C语言中的三种循环语句可以相互嵌套. 4.5 break语句 在一个循环程序中,可以通过循环语句中的表达式来控制循环程序是否结束,除此之外, 还可以通过break语句强行退出循环结构. 例4:开机后,全部LED不亮,按下K1则从LED1开始依次点亮,至LED8后停止并 全部熄灭,等待再次按下K1键,重复上述过程.如果中间K2键被按下,LED立即全部熄灭,返回起始状态. #include "reg51.h" #include"intrins.h" //该文件包含有_crol_( )函数的说明 void mDelay(unsigned int DelayTime) { unsigned int j=0; for(;DelayTime>0;DelayTime--) { for(j=0;j<125;j++) {;} } } void main() { unsigned char OutData=0xfe; unsigned char i; while(1) { P3|=0x3c; if((P3|0xfb)!=0xff) //K1键被按下 { OutData=0xfe; for(i=0;i<8;i++) { mDelay(1000); /*延时1000毫秒*/ tmp=0xfe; 单片机的C语言轻松入门 33 if((P3|0xf7)!=0xff) //K2键被按下 break; OutData=_crol_(OutData,i); P1&=OutData; } } P1=0xff; } } 请读者输入程序,建立工程,使用实验仿真板或者实验板来验证这一功能,注意,K2 按下的时间必须足够长,因为这里每1s才会检测一次K2是否被按下. 程序分析:开机后,当检测到K1键被按下,执行一个: for(i=0;i0;DelayTime--) { for(j=0;jStop Runing停止运行,实际上这不会中 断硬件电路的工作; 3.打开PC端串口调试软件,正确设置串口参数,即可正常工作. 单片机的C语言轻松入门 40 第六章C语言编程综合练习 前面课程中我们学习了单片机C语言的基本知识,了解了单片机内部资源的C语言编程方法,这一节通过若干例子进一步学习C语言程序的有关知识点. 1. 计数器 要求:编写一个计数器程序,将T0作为计数器来使用,对外部信号计数,将所计数字 显示在数码管上. 该部分的硬件电路如图6-1所示,U1的P0口和P2口的部份引脚构成了6位LED数码管驱动电路,数码管采用共阳型,使用PNP型三极管作为片选端的驱动,所有三极管的发射极连在一起,接到正电源端,它们的基极则分别连到P2.0 P2.5,当P2.0 P2.5中某引脚输是低电平时,三极管导通,给相应的数码管供电,该位数码管点亮哪些笔段,则取决于笔段引脚是高或低电平.图中看出,所有6位数码管的笔段连在一起,通过限流电阻后接到P0口,因此,哪些笔段亮就取决于P0口的8根线的状态. 编写程序时,首先根据硬件连线写出LED数码管的字形码,位驱动码,然后编写程序 如下: #include "reg51.h" #define uchar unsigned char #define uint unsigned int uchar code BitTab[]={0x7F,0xBF,0xDF,0xEF,0xF7,0xFB}; //位驱动码 uchar code DispTab[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x8 6,0x8E,0xFF}; //字形码 uchar DispBuf[6]; //显示缓冲区 图6-1 计数器实验硬件电路图 单片机的C语言轻松入门 41 void Timer1() interrupt 3 { uchar tmp; uchar Count; //计数器,显示程序通过它得知现正显示哪个数码管 TH1=(65536-3000)/256; TL1=(65536-3000)%256; //重置初值 tmp=BitTab[Count]; //取位值 P2=P2|0xfc; //P2与11111100B相或 P2=P2&tmp; //P2与取出的位值相与 tmp=DispBuf[Count];//取出待显示的数tmp=DispTab[tmp]; //取字形码 P0=tmp; Count++; if(Count==6) Count=0; } void main() { uint tmp; P1=0xff; P0=0xff; TMOD=0x15; //定时器0工作于计数方式1,定时器1工作于定时方式1 TH1=(65536-3000)/256; TL1=(65536-3000)%256; //定时时间为3000个周期 TR0=1; //计数器0开始运行 TR1=1; EA=1; ET1=1; for(;;) { tmp=TL0|(TH0<<8); //取T0中的数值 DispBuf[5]=tmp%10; DispBuf[4]=tmp%10; tmp/=10; tmp/=10; DispBuf[3]=tmp%10; tmp/=10; DispBuf[2]=tmp%10; DispBuf[1]=tmp/10; DispBuf[0]=0; } } 42 这个程序中用到了一个新的知识点,即数组,首先作一个介绍. 数组是C51的一种构造数据类型,数组必须由具有相同数据类型的元素构成,这些数 据的类型就是数组的基本类型,如:数组中的所有元素都是整型,则该数组称为整型数组, 如所有元素都是字符型,则该数组称为字符型数组. 数组必须要先定义,后使用,这里仅介绍一维数组的定义,其方式为: 类型说明符数组名[整型表达式] 定义好数组后,可以通过:数组名[整型表达式]来使用数组元素. 在定义数组时,可以对数组进行初始化,即给其赋予初值,这可用以下的一些方法实现: 1. 在定义数组时对数组的全部元素赋予初值: 例:int a[5]={1,2,3,4,5}; 2. 只对数组的部分元素初始化; 例:int a[5]={1,2}; 上面定义的a数组共有5个元素,但只对前两个赋初值,因此a[0]和a[1]的值是1,2, 而后面3个元素的值全是0. 3. 在定义数组时对数组元素的全部元素不赋初值,则数组元素值均被初始化为0 4. 可以在定义时不指明数组元素的个数,而根据赋值部分由编译器自动确定 例:uchar BitTab[]={0x7F,0xBF,0xDF,0xEF,0xF7,0xFB}; 则相当于定义了一个BitTab[6]这样一个数组. 5.可以为数组指定存储空间,这个例子中,未指定空间时,将数组定义在内部RAM 中,可以用code关键字将数组元素定义在ROM空间中. uchar code BitTab[]={0x7F,0xBF,0xDF,0xEF,0xF7,0xFB}; 用这两种定义分别编译,可以看出使用了code关键字后系统占用的RAM数减少了, 这种方式用于编程中不需要改变内容的场合,如显示数码管的字形码等是很合适的. 6.C语言并不对越界使用数组进行检测,例如上例中数组的长度是6,其元素应该是 从BitTab[0]~BitTab[5],但是如果你在程序中写上BitTab[6],编译器并不会认为这有语法错误,也不会给出警告(其他语言如BASCI等则有严格的规定,这种情况将视为语法错误), 因此,编程者必须自己小心确认这是否是你需要的结果. 程序分析:程序中将定时器T1用作数码管显示,通过interrupt 3关键字定义函数Timer1() 为定时器1中断服务程序,在这个中断服务程序中,使用 TH1=(65536-3000)/256; TL1=(65536-3000)%256; 来重置定时器初值,这其中3000即为定时周期,这样的写法可以直观地看到定时周期数, 是常用的一种写法.其余程序段分别完成取位码以选择数码管,从显示缓冲区获得待显示数值,根据该数值取段码以点亮相应笔段等任务.其中使用了一个计数器,该计数器的值从 0~5对应第1到第6位的数码管. 主程序的第一部分是做一些初始化的操作,设置定时器工作模式,开启定时器T1,开 启计数器T0,开启T1中断及总中断,随后进入主循环,主循环首先用unsigned int型变量tmp取出T0中的数值,这里使用了"tmp=TL0|(TH0<<8);"这样的形式,这相当于 tmp=TH0*256+TL0,但比之于后一种形式,该方式可以得到更高的效,其后就是将tmp值 不断地除10取整,这样将int型数据的各位分离并送入相应的显示缓冲区. 二,液晶显示 字符型液晶显示器用于显示数字,字母,图形符号.这类显示器均把LCD控制器,点 43 阵驱动器,字符存贮器等做在一块板上,再与液晶屏一起组成一个显示模块,因此,这类显示器安装与使用都较简单. 图6-2是DSB-1A实验板上字符型液晶的接口电路.要求编写程序从该显示器的第二行第1列开始显示"Hello World!". 由于市面上常见的字符型液晶驱动器均由HD44780或其兼容芯片构成,因此,这类液 晶屏的驱动程序具有一定的通用性,这里给出用C语言写的驱动程序.在设置字符的起始行,列后,直接调用驱动程序提供的WriteString函数即可将字符串显示在指定的位置,使用非常简单.在熟悉了程序后,略作改动,可用于2002,2004等型号的液晶屏. 程序如下: /************************************************** * 平凡单片机工作室 * https://www.360docs.net/doc/3d16494387.html, * Copyright 2003 pingfan's McuStudio * All rights Reserved *作者:周坚 *yj.c *连线图: * DB0---DPROT.0 DB4---DPROT.4 RS-------------P2.5 * DB1---DPROT.1 DB5---DPROT.5 RW-------------P2.6 * DB2---DPROT.2 DB6---DPROT.6 E--------------P2.7 * DB3---DPROT.3 DB7---DPROT.7 VLCD接10K可调电阻到GND* *80C51的晶振频率为12MHz *液晶显示程序 ***************************************************/ #include "reg51.h" #include #include #define DPORT P0 #define uchar unsigned char sbit RS = P2^5; sbit RW = P2^6; sbit E = P2^7; 图6-2 字符型液晶与单片机的接线图 DA TA PORT P0.0DB0 P0.7DB7 RS R/W E P2.5 P2.6 P2.7 +5V GND VL BLK BLA 80C51 单片机的C语言轻松入门 44 uchar Xpos; //列方向地址指针 uchar Ypos; //行方向地址指针 #define NoDisp 0 #define NoCur 1 #define CurNoFlash 2 #define CurFlash 3 /*延时程序 由Delay参数确定延迟时间 */ void LcdWcn(uchar); void LcdWc(uchar); void WriteChar(uchar); void LcdPos(); void LcdWd(uchar); void LcdWdn(uchar); void mDelay(unsigned int Delay) { unsigned int i; for(;Delay>0;Delay--) { for(i=0;i=15) //每行最多显示16个字符 break; } } void main() { uchar s1[]="Hellow World!"; RstLcd(); //复位LCD ClrLcd(); SetCur(CurFlash); //光标显示且闪烁 Xpos=2; Ypos=1; WriteString(s1); for(;;) {;} } 程序分析:本程序中大量使用了函数,在此对函数的功能作一个简介. C语言程序是由一个个函数构成的,从函数定义的形式上划分,函数有三种形式:无参数函数,有参数函和空函数. 无参数函数的定义形式为: 返回值类型识别符函数名(){函数体语句} 如本例中的void WaitIdle(){ …… }就是一个无参数函数 有参数函数的定义形式为: 返回值类型识别符函数名(形式参数列表){函数体语句} 如本例中的void LcdWdn(uchar c){ …… }就是一个有参数的函数 函数可以返回一个值,也可以什么值也返回,如果函数要返回一个值,在定义这个函数 时要定义好这个值的数据类型,这里所说的数据类型就是指前面课程中介绍到的int,char, float等类型,如果在定义函数时没有定义返回值的类型,系统默认为返回一个int型的值. 如果明确地知道一个函数将没有返回值,可以将其定义为void型,这样,如果在调用函数单片机的C语言轻松入门 48 时错误地使用了"变量名=函数名"的方式来调用函数,编译器就能发现这一错误并指出. 本例中就大量地应用到了void型函数. C语言采用函数之间的参数传递方式,这使得一个函数能对不同的变量进行功能相同的处理,使函数具有了通用性.定义函数时,写在函数名括号中的称之为形式参数,而在实际 调用函数时写在函数括号中的称之为实际参数.本例中: void SetCur(uchar Cur) { …} 函数中Cur就是一个形式参数,而在主函数中调用时写的: SetCur(CurFlash); 其中CurFlash就是一个用符号常量表示的实际参数,在执行该函数时该值被传递到函 数内部并执行. 每一个函数所调用的函数必须已被定义,否则就会出现语法错误,因此程序中一般要求 在程序的开头对程序中用到的函数进行统一的说明,然后再分别定义有关函数,本例中有: void WriteChar(uchar); … void LcdWdn(uchar); 就是首先在程序的前方写一个有关函数的说明,而真正的函数定义则在程序放在后部. 但细心的读者可能发现有一些函数并未写其说明,而是直接在程序中定义了,如mDelay函数,这是为何呢这是因为这些函数出现在程序的前面,在还没有任何函数调用它们之前它们就被定义了,因此就不需要再单独写一个函数说明.读者可将mDelay函数的定义移到程序的后面位置,再次编译就会出错.当然,好的编程习惯是不论函数在何处被定义,总是在 写前面写一个函数说明. 有关单片机的C语言编程到此就告一个段落,虽然C语言很多特性尚未介绍,但通过 上面有关内容的学习,我们已经可以使用C语言进行一些实际的工程开发工作,大家可以在工作中继续学习有关C语言的知识. } 目录 目录 (1) 函数的使用和熟悉********************************/ (4) 实例3:用单片机控制第一个灯亮 (4) 实例4:用单片机控制一个灯闪烁:认识单片机的工作频率 (4) 实例5:将P1口状态分别送入P0、P2、P3口:认识I/O口的引脚功能 (5) 实例6:使用P3口流水点亮8位LED (5) 实例7:通过对P3口地址的操作流水点亮8位LED (6) 实例8:用不同数据类型控制灯闪烁时间 (7) 实例9:用P0口、P1口分别显示加法和减法运算结果 (8) 实例10:用P0、P1口显示乘法运算结果 (9) 实例11:用P1、P0口显示除法运算结果 (9) 实例12:用自增运算控制P0口8位LED流水花样 (10) 实例13:用P0口显示逻辑"与"运算结果 (10) 实例14:用P0口显示条件运算结果 (11) 实例15:用P0口显示按位"异或"运算结果 (11) 实例16:用P0显示左移运算结果 (11) 实例17:"万能逻辑电路"实验 (11) 实例18:用右移运算流水点亮P1口8位LED (12) 实例19:用if语句控制P0口8位LED的流水方向 (13) 实例20:用swtich语句的控制P0口8位LED的点亮状态 (13) 实例21:用for语句控制蜂鸣器鸣笛次数 (14) 实例22:用while语句控制LED (16) 实例23:用do-while语句控制P0口8位LED流水点亮 (16) 实例24:用字符型数组控制P0口8位LED流水点亮 (17) 实例25:用P0口显示字符串常量 (18) 实例26:用P0口显示指针运算结果 (19) 实例27:用指针数组控制P0口8位LED流水点亮 (19) 实例28:用数组的指针控制P0口8位LED流水点亮 (20) 实例29:用P0、P1口显示整型函数返回值 (21) 实例30:用有参函数控制P0口8位LED流水速度 (22) 实例31:用数组作函数参数控制流水花样 (23) 实例32:用指针作函数参数控制P0口8位LED流水点亮 (23) 实例33:用函数型指针控制P1口灯花样 (25) 实例34:用指针数组作为函数的参数显示多个字符串 (26) 实例35:字符函数ctype.h应用举例 (27) 实例36:内部函数intrins.h应用举例 (27) 实例37:标准函数stdlib.h应用举例 (28) 实例38:字符串函数string.h应用举例 (29) 实例39:宏定义应用举例2 (29) 1/192 广州康大职业技术学院 《单片机C语言程序设计》课程标准 一、基本信息 适用对像:应用电子技术专业的学生 课程代码: 学分:2 学时:36 制定人:徐又又 制定时间:2010年9月 所属系部:自动化 批准人:陶甫廷 二、课程的目标 1.专业能力目标 了解单片机C语言的特点、与PC机C语言的异同之处、单片机C语言的开发环境; 熟悉单片机C语言的基本语法规范、Keil C软件的应用及其与硬件平台的连接、C语言程 序结构设计、与单片机相关的设置等方面知识。 2.方法能力目标 了解用单片机C语言进行应用产品软件开发的步骤,具备单片机C语言程序的识读、修改的基本能力;学会使用Keil C软件进行源程序编辑、编译和软、硬件模拟调试的操作方 法与技能。 3.社会能力目标 通过后续课程《单片机应用实训》的学习与强化训练,具有使用单片机C语言进行电子产品、自动检测与控制和高新视听设施等方面的软件开发的职业技能。 三、整体教学设计思路 1.课程定位 该课程是应用电子技术和自动化技术等专业获得专业技能的必修课程之一,该课程属于职业技术课程,以培养电子产品开发相关行业急需的机电类和电子类高级技能应用型人才 为目标。 本课程一般在学生学完模拟电子技术与数字电子技术、计算机技术等专业基础课后再讲授;《单片机应用》等课程可作为先修课程,也可在同一学期开设。 2.课程开发思路 本课程根据“工学结合”的原则,强调对单片机C语言程序设计的理论部分删繁就简,以“实用够用”为度,就是为了便于他们在后续的实训月(四周)以及即将下厂顶岗实习期 (十周),将所学的单片机C语言程序设计的常用原理与实用知识,能够与实训、实习的生 产工位和顶岗工作更紧密地联系起来。 四、教学内容 1.学时分配 学习情境名称子学习情境1 子学习情境2 子学习情境3 子学习情境4 学时 分配 学习情境(单元)1 单片机C语言概述单片机C语言与 PC机C语言的异 同之处 简单的C程序介绍 及上机操作(编译 三个简单C程序) 3 教学时数 1 2 学习情境(单元)2单片机C语言开发环境 建立 Keil软件的使 用(源文件、 工程的建立) 上机操作(用keil 软件进行工程的设 置) 3 教学时数 2 1 学习情境(单元)3数据的类型、运算符和 表达式 用整型和字符型 定义变量 数的溢出 C51中特有的数 据类型 上机操作(用 算术运算符和 算术表达式编 写程序) 6 教学时数 2 1 2 1 学习情境(单元)4C51流程与控制顺序结构程序选择结构程序循环结构程 序(上机操作 编译冒泡排 序法程序) 6 教学时数 2 2 2 学习情 境(单 元)5 C51构造数据类型数组指针结构共用体和枚举 6 教学时数 2 2 1 1 学习情境(单元)6单片机内部资源的组成中断编程上机操作用定时器 /计数器资源 编程并编译 串口编程 6 教学时数 2 2 2 学习情境(单元)7函数函数的定义函数的调用局部变量和全局 变量 变量的存储类 别 6 教学时数 2 2 1 1 单片机C语言编程实例 前言 INTEL公司的MCS-51单片机是目前在我国应用得最广泛的单片机之一.随着 单片机应用技术的不断发展,许多公司纷纷以51单片机为内核,开发出与其兼容的 多种芯片,从而扩充和扩展了其品种和应用领域。 C语言已成为当前举世公认的高效简洁而又贴近硬件的编程语言之—。将C语言向单片机上的移植,始于20世纪80年代的中后期。经过十几年的努力,C语言终于成为专业化单片机上的实用高级语言。用C语言编写的8051单片机的软件,可以大大缩短开发周期,且明显地增加软件的可读性,便于改进和扩充,从而研制出规模更大、性能更完善的系统。因此,不管是对于新进入这一领域的开发者来说,还是对于有多年单片机开发经验的人来说,学习单片机的C语言编程技术都是十分必要的。. C语言是具有结构化.模块化编译的通用计算机语言,是国际上应用最广.最多的计算语言之一。C51是在通用C语言的基础上开发出的专门用于51系列单片机编程的C语言.与汇编语言相比,C51在功能上.结构上以及可读性.可移植性.可维护性等方面都有非常明显的优势。目前 最先进、功能最强大、国内用户最多的C51编译器是Keil Soft ware公司推出的KeilC51。第 一章单片机C语言入门 1.1建立您的第一个C项目 使用C语言肯定要使用到C编译器,以便把写好的C程序编译为机器码, 这样单片机才能执行编写好的程序。KEIL uVISION2是众多单片机应用开发软 件中优秀的软件之一,它支持众多不同公司的MCS51架构的芯片,它集编辑, 编译,仿真等于一体,同时还支持PLM、汇编和C语言的程序设计,它的界面 和常用的微软VC++的界面相似,界面友好,易学易用,在调试程序,软件仿真 方面也有很强大的功能。因此很多开发51应用的工程师或普通的单片机爱好者,都对它十分喜欢。 以上简单介绍了KEIL51软件,要使用KEIL51软件,必需先要安装它。KEIL51是一个商业的软件,对于我们这些普通爱好者可以到KEIL中国代理周 立功公司的网站上下载一份能编译2K的DEMO版软件,基本可以满足一般的个 说了这么多了,相信你也看了很多资料了,手头应该也有必备的工具了吧!(不要忘了上面讲过几个条件的哦)。那个单片机究竟有什么 功能和作用呢?先不要着急!接下来让我们点亮一个LED(搞电子的应该知道LED是什么吧^_^) 我们在单片机最小系统上接个LED,看我们能否点亮它!对了,上面也有好几次提到过单片机最小系统了,所谓单片机最小系统就是在单片机 上接上最少的外围电路元件让单片机工作。一般只须连接晶体、VCC、GND、RST即可,一般情况下,AT89C51的31脚须接高电平。 #include 单片机C语言程序设计师试题 一、填空题 1、设X=5AH,Y=36H,则X与Y“或”运算为_________,X与Y的“异或”运算为________。 2、若机器的字长为8位,X=17,Y=35,则X+Y=_______,X-Y=_______(要求结果写出二进制形式)。 3、单片机的复位操作是__________(高电平/低电平),单片机复位后,堆栈指针SP的值是________。 4、单片机中,常用作地址锁存器的芯片是______________,常用作地址译码器芯片是_________________。 5、若选择内部程序存储器,应该设置为____________(高电平/低电平),那么,PSEN信号的处理方式为__________________。 6、单片机程序的入口地址是______________,外部中断1的入口地址是_______________。 7、若采用6MHz的晶体振荡器,则MCS-51单片机的振荡周期为_________,机器周期为_______________。 8、外围扩展芯片的选择方法有两种,它们分别是__________________和_______________。 9、单片机的内部RAM区中,可以位寻址的地址范围是__________________,特殊功能寄存器中,可位寻址的地址是____________________。 10、子程序返回指令是________,中断子程序返回指令是_______。 11、8051单片机的存储器的最大特点是____________________与____________________分开编址。 12、8051最多可以有_______个并行输入输出口,最少也可以有_______个并行口。 13、_______是C语言的基本单位。 14、串行口方式2接收到的第9位数据送_______寄存器的_______位中保存。 15、MCS-51内部提供_______个可编程的_______位定时/计数器,定时器有_______种工作方式。 16、一个函数由两部分组成,即______________和______________。 17、串行口方式3发送的第9位数据要事先写入___________寄存器的___________位。 18、利用8155H可以扩展___________个并行口,___________个RAM单元。 19、C语言中输入和输出操作是由库函数___________和___________等函数来完成。 二、选择题 1、C语言中最简单的数据类型包括(b )。 A、整型、实型、逻辑型 B、整型、实型、字符型 C、整型、字符型、逻辑型 D、整型、实型、逻辑型、字符型 2、当MCS-51单片机接有外部存储器,P2口可作为( c )。 A、数据输入口 B、数据的输出口 C、准双向输入/输出口 D、输出高8位地址 3、下列描述中正确的是( d )。 A、程序就是软件 B、软件开发不受计算机系统的限制 C、软件既是逻辑实体,又是物理实体 D、软件是程序、数据与相关文档的集合 4、下列计算机语言中,CPU能直接识别的是( d )。 A、自然语言 B、高级语言 C、汇编语言 D、机器语言 5、MCS-5l单片机的堆栈区是设置在( c )中。 2013-2014学年上期51单片机C语言程序设计重修复习提纲考试方式:闭卷考试。 考试题型: 填空题(每空1分,共18分);单项选择题(每空2分,共18分);问答及计算题(每题4分,共16分);编程及程序阅读题(5小题,共48分)。 考试分数: 卷面成绩70%+平时成绩15%+实验成绩15%,未缺席、无课堂违纪、作业全交且认真完成的同学平时成绩可获得满分,缺席一次平时成绩扣30分,实验好评次数3次以上且实验报告全优的同学实验成绩可得满分,实验缺席一次扣30分。缺席实验和旷课共3次以上者,无考试资格。 考试时间: 18周周一(12月30日)下午14:00:16:00,考试地点:具体考室另行通知希望大家认真复习,认真听讲,不懂就问,考试成绩不及格允许查卷,如查卷卷面批阅无误成绩不做更改。 编程题为实验或实验类似的题目有3题,其余2题也取自课堂讲授例题,请务必认真复习。第一章单片机概述及单片机知识回顾 掌握什么是单片机、单片机的应用、常见单片机类型、十进制、十六进制、二进制数制转换知识。掌握单片机的硬件组成、CPU的结构、程序计数器PC的功能、存储器结构、机器周期的计算、会画出单片机的最小系统电路图及回答单片机最小系统的组成。 第二章C51语言程序设计基础(本章填空题和选择题比重较大请务必认真复习)掌握C51语言进行软件开发与汇编语言相比的优点、掌握C51的数据类型、特殊功能位的定义、C51的基本运算(位运算重点复习)、数组的定义、C51的结构及函数。 第三章AT89S51片内并行端口及编程(本章有编程题) 掌握P0-P3并行端口的特点,会开关量检测及流水灯程序的编程。 第四章AT89S51单片机的中断系统(本章有编程题) 掌握中断系统的结构、中断请求响应被满足的条件、外部中断的触发选择方式、外部中断的使用与编程。 第五章AT89S51单片机的定时器/计数器(本章有编程器) 掌握定时器的结构,TOMD及TCON的使用,定时器方式0和方式1的特点、会计算定时器初值,会用定时器中断产生PWM波形,会用定时器对外部事件进行计数。 第六章AT89S51单片机的串行口(本章有计算题) 掌握串行通信的基础知识(课本没有的内容请参照课堂讲授笔记或PPT)、串行口的四种工作方式的特点、会计算奇偶校验码、会根据波特率计算T1的初值。 第七章AT89S51单片机与输入/输出外设接口(本章有编程题) 掌握数码管动态显示的原理、掌握矩阵式键盘的原理与编程(矩阵键盘编程必考,但不会考4X4键盘)。 第八章AT89S51单片机与D/A与A/D转换器的接口(本章有编程题) 掌握AD与DA转换的接口、ADC和DAC的技术指标、常用AD和DA转换器。掌握ADC0809和TLC2543的使用与编程(2器件其中之一有编程题)。 第九章AT89S51单片机应用系统与调试(本章有编程题) 掌握单片机应用系统的软件抗干扰方法。 《单片机C语言程序设计实训100例—基于8051+Proteus仿真》案例 令狐采学 第01 篇基础程序设计 01闪烁的LED /* 名称:闪烁的LED 说明:LED按设定的时间间 隔闪烁 */ #include for(i=0;i<120;i++); } } //主程序 void main() { while(1) { LED=~LED; DelayMS(150); } } 02 从左到右的流水 灯 /* 名称:从左到右的 流水灯 说明:接在P0口的8 个LED从左到右循环依次点亮,产生走马灯效果*/ #include //延时 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_形成来回滚动的效果 《51单片机C语言程序设计》实验教学指导书 伍勤谟编 二00六年十二月 单片机C语言实践教学的内容目录 实验一单片机C语言编程环境建立 实验目的:掌握Keil软件的安装,使用; 实验内容:Keil软件的安装,使用, 熟悉单片机C语言编程过程(源文件的建立,工程的建立,编译及链接等) 实验仿真板的介绍及使用等; 实验二51 C 语言数据类型,运算符与表达式的练习(1) 实验目的:掌握相关语句的编程方法。 实验内容:演示字符型数据和整型数据的溢出. 观察浮点型数据在内存中的存放方式; 演示实型数据的舍入误差; 观察数据在内存中的存储位置 实验三51 C 语言数据类型,运算符与表达式的练习(2) 实验目的:掌握相关语句的编程方法。 实验内容:定义多个变量观察各自的存储空间; 将变量定义在位变量变区; 研究pdata和xdata型变量的存储空间; 观察各种类型数据转换时的内存变化; 实验四51 C 语言程序流程控制语句的练习 实验目的:掌握for、while do---while等循环语句的编程方法。 实验内容:利用仿真型实验板和所学流程控制语句,编写演示流水灯功能的程序。 实验五51 C 语言的构造数据类型的练习 实验目的: 1 熟悉51 C 语言的指针与数组的语法结构。 2 掌握指针与数组的编程的方法。 实验内容:编写程序:通过指针变量访问整型变量 实验六51 单片机内部资源C 语言的编程练习 实验目的:掌握51 单片机内部资源C 语言编程的方法。 实验内容:编写利用外中断控制实验LED灯亮灭程序;利用定时器的中断方式控制实验板上LED闪烁功能,要求每50ms改变一次。 实验七51 单片机内部资源C 语言的编程练习 实验目的:掌握51 单片机内部资源C 语言编程的方法。 实验内容:编写利用定时器控制实验板两个灯的同时闪烁,但它们的闪烁时间不同;利用计数器功能将T0口计数值显示出来(用8个LED来显示数据)。 实验八51 C 语言的涵数语句的练习 实验目的: 1、掌握51 C 语言的涵数语句与程序结构。 2、掌握51 C 语言的涵数参数传递与调用。 实验内容:编写程序:求1个数的阶乘 实验九51单片机接口C 语言编程的练习 实验目的:掌握51单片机接口C 语言编程基本方法。 实验内容:编写实验板六位数码管动态显示程序,要求:使用定时中断实现显示的程序,第1~5位各位始终显示0,第六位在0~9之间显示。 实验十51单片机应用设计举例练习 实验目的:掌握51单片机应用设计方法。 实验内容:编写程序:用实验板实现秒钟功能,且有高位消隐功能。 项目三C51程序设计语言基础 任务1 C51程序的识读 1.C51程序结构 例3-1 P_test /********************* //注释,还可用//注释掉一行 File name:P_test.c Chip name:STC89C51RC Clock frequency:1.20MHz ***********************/ #include “reg52.h”//预处理命令,文件包含预处理命令,后缀名都是.h,标准的MCS-51单片机头文件为”reg51.h”,STC89系列单片机头文件为”reg52.h” #define unit unsigned int //宏定义预处理命令 sbit BZ=P3`7 ; sbit key=P1`0; void delay(unit ms) { unit i; while( ms --) { for(i=0;i<120;i++); } } void main(void) { while(1) { if(key==0) { BZ=0x0; delayms(10); BZ=0x1; delayms(50); P0=0xFF; } else { P0=~P0; delayms(500); } } } 2.C51的数据类型 位变量型bit 字符型无符号字符型unsigned char 有符号字符型signed char C51的数据类型整数型无符号整数型unsigned int 基本类型有符号整数型signed int 长整数型无符号长整数型unsigned long int 有符号长整数型signed long int 实数型(浮点型)单精度浮点型float 双精度浮点型double 数组类型array 结构体类型struct 构造类型共用体union 枚举enum 指针类型 空类型(void) 表3-1 C51基本数据类型的长度和值域 类型长度/bit 长度/byte 范围 位变量型bit 1 0 ,1 无符号字符型unsigned char 8 单字节0-255 有符号字符型signed char 8 单字节-128-127 无符号整数型unsigned int 16 双字节0-65536 有符号整数型signed int 16 双字节-32768-32767 无符号长整数型unsigned long int 32 四字节 有符号长整数型signed long int 32 四字节 单精度浮点型float 32 四字节 双精度浮点型double 32 四字节 一般指针类型24 三字节 3.C51的标识符和关键字 标识符是由字母、数字和下划线组成的字符串,第一个字符必须是字母或下划线,不超过32个字符。 表3-2 C51中的关键字 关键字用途说明 auto 存储种类声明用来声明局部变量 bdata 存储器类型说明可位寻址的内部数据存储器 break 程序语句退出最内层循环体 bit 位变量语句位变量的值是1(true)或0(flase)case 程序语句switch语句中的选择项 char 数据类型的声明单字节整数型或字符型数据 本文由fan159147贡献 doc文档可能在WAP端浏览体验不佳。建议您优先选择TXT,或下载源文件到本机查看。 《8051 单片机 C 语言编程模板》 杜洋 2009.7 [程序开始处的程序说明] /****************************************************************************** *************** 程序名: 编写人: 杜洋 编写时间: 20 年 月 日 硬件支持: 接口说明: 修改日志: NO.1/****************************************************************************** *************** 说明: /****************************************************************************** ***************/ [单片机 SFR 定义的头文件] #include <REG51.h> //通用 89C51 头文件 #include <REG52.h> //通用 89C52 头文件 #include //STC11Fxx 或 STC11Lxx 系列单片机头文件 #include //STC12Cx052 或 STC12Cx052AD 系列单片机头文件 #include //STC12C5A60S2 系列单片机头文件 [更多库函数头定义] #include #include <ctype.h> #include <errno.h> #include <float.h> #include <fstream.h> #include #include #include #include <locale.h> //设定插入点 //字符处理 //定义错误码 //浮点数处理 //文件输入/输出 //参数化输入/输出 //数据流输入/输出 //定义各种数据类型最值常量 //定义本地化函数 #include <math.h> #include #include #include #include #include <time.h> #include <wchar.h> #include <wctype.h> #include //定义数学函数 //定义输入/输出函数 //定义杂项函数及内存分配函数 //字符串处理 //基于数组的输入/输出 //定义关于时间的函数 //宽字符处理及输入/输出 //宽字符分类 //51 基本运算(包括_nop_空函数) [常用定义声明] sfr [自定义名] = [SFR 地址] ; //按字节定义 SFR 中的存储器名。例:sfr P1 = 0x90; sbit [自定义名] = [系统位名] ; //按位定义 SFR 中的存储器名。例:sbit Add_Key = P3 ^ 1; bit [自定义名] ; //定义一个位(位的值只能是 0 或 1)例:bit LED; #define [代替名] [原名] //用代替名代替原名。例:#define LED P1 / #define TA 0x25 unsigned char [自定义名] ; //定义一个 0 ̄255 的整数变量。例:unsigned char a; unsigned int [自定义名] ; //定义一个 0 ̄65535 的整数变量。例:unsigned int a; [定义常量和变量的存放位置的关键字] data 字节寻址片内 RAM,片内 RAM 的 128 字节(例:data unsigned char a;) bdata 可位寻址片内 RAM,16 字节,从 0x20 到 0x2F(例:bdata unsigned char a;) idata 所有片内 RAM,256 字节,从 0x00 到 0xFF(例:idata unsigned char a;) pdata 片外 RAM,256 字节,从 0x00 到 0xFF(例:pdata unsigned char a;) xdata 片外 RAM,64K 字节,从 0x00 到 0xFFFF(例:xdata unsigned char a;) code ROM 存储器,64K 字节,从 0x00 到 0xFFFF(例:code unsigned char a;) [选择、循环语句] if(1){ //为真时语句 }else{ //否则时语句 } while(1){ //为真时内容 } do{ //先执行内容 }while(1); switch (a){ case 0x01: //为真时语句 break; case 0x02: //为真时语句 break; default: //冗余语句 break; } for(;;){ //循环语句 } [主函数模板] /****************************************************************************** *************** 函数名:主函数 调 用:无 参 数:无 返回值:无 结 果:程序开始处,无限循环 备 注: /****************************************************************************** ****************/ void main (void){ //初始程序 while(1){ //无限循环程序 } } /****************************************************************************** ****************/ [中断处理函数模板] /****************************************************************************** *************** 函数名:中断处理函数 调 用:无 参 数:无 返回值:无 结 果: 备 注: /********************************* 目录 实例3:用单片机控制第一个灯亮 (3) 实例4:用单片机控制一个灯闪烁:认识单片机的工作频率 (3) 实例5:将 P1口状态分别送入P0、P2、P3口:认识I/O口的引脚功能 (4) 实例6:使用P3口流水点亮8位LED (4) 实例7:通过对P3口地址的操作流水点亮8位LED (5) 实例8:用不同数据类型控制灯闪烁时间 (6) 实例9:用P0口、P1 口分别显示加法和减法运算结果 (8) 实例10:用P0、P1口显示乘法运算结果 (8) 实例11:用P1、P0口显示除法运算结果 (9) 实例12:用自增运算控制P0口8位LED流水花样 (9) 实例13:用P0口显示逻辑"与"运算结果 (10) 实例14:用P0口显示条件运算结果 (10) 实例15:用P0口显示按位"异或"运算结果 (10) 实例16:用P0显示左移运算结果 (10) 实例17:"万能逻辑电路"实验 (11) 实例18:用右移运算流水点亮P1口8位LED (11) 实例19:用if语句控制P0口8位LED的流水方向 (12) 实例20:用swtich语句的控制P0口8位LED的点亮状态 (12) 实例21:用for语句控制蜂鸣器鸣笛次数 (14) 实例22:用while语句控制LED (15) 实例23:用do-while语句控制P0口8位LED流水点亮 (16) 实例24:用字符型数组控制P0口8位LED流水点亮 (16) 实例25:用P0口显示字符串常量 (17) 实例26:用P0 口显示指针运算结果 (18) 实例27:用指针数组控制P0口8位LED流水点亮 (18) 实例28:用数组的指针控制P0 口8 位LED流水点亮 (19) 实例29:用P0 、P1口显示整型函数返回值 (20) 实例30:用有参函数控制P0口8位LED流水速度 (21) 实例31:用数组作函数参数控制流水花样 (22) 实例32:用指针作函数参数控制P0口8位LED流水点亮 (23) 实例33:用函数型指针控制P1口灯花样 (24) 实例34:用指针数组作为函数的参数显示多个字符串 (25) 实例35:字符函数ctype.h应用举例 (26) 实例36:内部函数intrins.h应用举例 (27) 实例37:标准函数stdlib.h应用举例 (27) 实例38:字符串函数string.h应用举例 (28) 实例39:宏定义应用举例2 (28) 实例40:宏定义应用举例2 (29) 实例41:宏定义应用举例3 (29) 实例42:用定时器T0查询方式P2口8位控制LED闪烁 (30) 实例43:用定时器T1查询方式控制单片机发出1KHz音频 (31) 实例44:将计数器T0计数的结果送P1口8位LED显示 (31) 《基于8051+Proteus仿真》案例 第01 篇基础程序设计 01 闪烁的LED * 名称:闪烁的LED 说明:LED按设定的时间间隔闪烁 * #include P0=0xfe; while(1) { P0=_crol_(P0,1); P0的值向左循环移动 DelayMS(150); } } 03 8只LED左右来回点亮 * 名称:8只LED左右来回点亮 说明:程序利用循环移位函数_crol_和_cror_形成来回滚动的效果* #include DelayMS(150); } } } 04 花样流水灯 * 名称:花样流水灯 说明:16只LED分两组按预设的多种花样变换显示 * #include 《单片机C语言程序设计》期末考核项目 编制部门:电子信息工程技术专业编制人:张秀国审核人:编制日期:2013年6月18日 图1 模拟数字密码锁 一、基本考核要求:基于图1,编程实现下列功能。 开机显示如图2所示。 P A S S W O R D ■ 图2 开机显示画面 四、评分方法 1.完成基本考核要求,得60分 2.完成创新考核要求,加20分 3.项目报告中,流程图、知识点描述、难点及解决办法(10分),学习体会(10分) 出师表 两汉:诸葛亮 先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。 宫中府中,俱为一体;陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理;不宜偏私,使内外异法也。 侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下:愚以为宫中之事,事无大小,悉以咨之,然后施行,必能裨补阙漏,有所广益。 将军向宠,性行淑均,晓畅军事,试用于昔日,先帝称之曰“能”,是以众议举宠为督:愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。 亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之、信之,则汉室之隆,可计日而待也。 臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。 先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐托付不效,以伤先帝之明;故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。 愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言,深追先帝遗诏。臣不胜受恩感激。 今当远离,临表涕零,不知所言。 PIC单片机C语言编程实例——液晶显示模块编程 15.2.2 MG-12232模块的编程 下面以图15.1的接口电路为例。液晶显示区域分成E1边和E2边,下面只含E1边的程序(表15.1中E1=1,E2=0),E2边(表15.1中E1=0,E2=1)类推。 在系统程序的初始化部分,应对程序中用到的寄存器和临时变量作说明,如: unsigned char TRANS; unsigned char PAGEADD;//存放页地址寄存器 unsigned char PAGENUM;//存放总页数寄存器 unsigned char CLMSUM;//存放总列数寄存器 unsigned char CLMADD;//存放列地址寄存器 unsigned char WRITE;//存放显示数据寄存器 unsigned char row;//存放显示起始行寄存器 unsigned char i,k;//通用寄存器 //系统各口的输入输出状态初始化子程序 void INITIAL() { ADCON1=0X87;//设置PORTA口和PORTE口为数字I/O口 TRISA3=0; TRISB0=0; TRISE=0X00;//设置液晶的4个控制脚为输出 } //读液晶显示器状态子程序 void LCDSTA1() { while(1){ TRISD=0XFF;//设置D口为输入 RB0=1;//E1=1 RA3=0;//E2=0 RE0=1;//R/W=1 RE1=0;//A0=0 if(RD7==0) break;//为忙状态,则继续等待其为空闲 } } //对液晶显示器发指令子程序(指令保存在TRANS寄存器中) void TRANS1() { LCDSTA1();//判断液晶是否为忙 TRISD=0X00;//置D口为输出 RB0=1;//E1=1 RA3=0;//E2=0 RE0=0;//R/W=0 RE1=0;//A0=0 PORTD=TRANS;//需要写入的命令字送入数据线 RB0=0;//E1=0写入指令 基础知识:C51单片机编程基础 单片机的外部结构: 1.DIP40双列直插; 2.P0,P1,P2,P3四个8位准双向I/O引脚;(作为I/O输入时,要先输出高电平) 3.电源VCC(PIN40)和地线GND(PIN20); 4.高电平复位RESET(PIN9);(10uF电容接VCC与RESET,即可实现上电复位) 5.内置振荡电路,外部只要接晶体至X1(PIN18)和X0(PIN19);(频率为主频的 12倍) 6.程序配置EA(PIN31)接高电平VCC;(运行单片机内部ROM中的程序) 7.P3支持第二功能:RXD、TXD、INT0、INT1、T0、T1 单片机内部I/O部件:(所为学习单片机,实际上就是编程控制以下I/O部件,完成指定任务) 1.四个8位通用I/O端口,对应引脚P0、P1、P2和P3; 2.两个16位定时计数器;(TMOD,TCON,TL0,TH0,TL1,TH1) 3.一个串行通信接口;(SCON,SBUF) 4.一个中断控制器;(IE,IP) 针对AT89C52单片机,头文件AT89x52.h给出了SFR特殊功能寄存器所有端口的定义。 C语言编程基础: 1.十六进制表示字节0x5a:二进制为01011010B;0x6E为01101110。 2.如果将一个16位二进数赋给一个8位的字节变量,则自动截断为低8位,而丢掉 高8位。 3.++var表示对变量var先增一;var—表示对变量后减一。 4.x |= 0x0f;表示为x = x | 0x0f; 5.TMOD = ( TMOD & 0xf0 ) | 0x05;表示给变量TMOD的低四位赋值0x5,而不改变 TMOD的高四位。 6.While( 1 ); 表示无限执行该语句,即死循环。语句后的分号表示空循环体,也就是 {;} 在某引脚输出高电平的编程方法:(比如P1.3(PIN4)引脚) 代码C51单片机C语言程序100例_Keil
《单片机C语言程序设计》课程标准
单片机C语言编程实例
单片机c语言编程控制流水灯
单片机C语言程序设计师试题及答案
51单片机C语言程序设计复习资料
单片机C语言程序设计实训100例--基于8051+PROTEUS仿真1
51单片机C语言程序设计实验
51单片机C语言程序设计经典案例
8051单片机C语言编程模板
51单片机C语言编程100例
(完整版)单片机C语言程序设计实训100例—基于8051+Proteus仿真毕业论文
《单片机C语言程序设计》期末考核项目
PIC单片机C语言编程实例
C51单片机C语言编程基础和实例