如何构建单片机程序框架

如何构建单片机程序框架
如何构建单片机程序框架

如何构建单片机程序框架

任何对时间要求苛刻的需求都是我们的敌人,在必要的时候我们只有增加硬件成本来消灭它;比如你要8个数码管来显示,我们在没有相关的硬件支持的时候必须用MCU以动态扫描的方式来使其工作良好;而动态扫描将或多或少的阻止了MCU处理其他的事情。在MCU负担很重的场合,我会选择选用一个类似max8279外围ic来解决这个困扰;

然而庆幸的是,有着许多不是对时间要求苛刻的事情:

例如键盘的扫描,人们敲击键盘的速率是有限的,我们无需实时扫描着键盘,甚至可以每隔几十ms才去扫描一下;然而这个几十ms的间隔,我们的MCU还可以完成许多的事情;

单片机虽然是裸机奔跑,但是往往现实的需要决定了我们必须跑出操作系统的姿态——多任务程序;

比如一个常用的情况有4个任务:

1键盘扫描;

2led数码管显示;

3串口数据需要接受和处理;

4串口需要发送数据;

我们可以借助实验板来实践这些

如何来构架这个单片机的程序将是我们的重点;

读书时代的我会把键盘扫描用查询的方式放在主循环中,而串口接收数据用中断,在中断服务函数中组成相应的帧格式后置位相应的标志位,在主函数的循环中进行数据的处理,串口发送数据以及led的显示也放在主循环中;

这样整个程序就以标志变量的通信方式,相互配合的在主循环和后台中断中执行;

然而必须指出其不妥之处:

每个任务的时间片可能过长,这将导致程序的实时性能差。如果以这样的方式在多加几个任务,使得一个循环的时间过长,可能键盘扫描将很不灵敏。所以若要建立一个良好的通用编程模型,我们必须想办法,消去每个任务中费时间的部分以及把每个任务再次分解;下面来细谈每个任务的具体措施:

1键盘扫描

键盘扫描是单片机的常用函数,以下指出常用的键盘扫描程序中,严重阻碍系统实时性能的地方;

众所周知,一个键按下之后的波形是这样的(假定低有效):

在有键按下后,数据线上的信号出现一段时间的抖动,然后为低,然后当按键释放时,信号抖动一段时间后变高。当然,在数据线为低或者为高的过程中,都有可能出现一些很窄的干扰信号。

unsigned char kbscan(void)

{

unsigned char sccode,recode;

P2=0xf8;

if((P2&0xf8)!=0xf8)

{

delay(100);//延时20ms去抖--------这里太费时了,很糟糕

if((P2&0xf8)!=0xf8)

{

sccode=0xfe;

while((sccode&0x08)!=0)

{

P2=sccode;

if((P2&0xf8)!=0xf8)

break;

sccode=(sccode<<1)|0x01;

}

recode=(P2&0xf8)|0x0f;

return(sccode&recode);

}

}

return(KEY_NONE);

}

键盘扫描是需要软件去抖的,这没有争议,然而该函数中用软件延时来去抖(ms 级别的延时),这是一个维持系统实时性能的一个大忌讳;

一般还有一个判断按键释放的代码:

While(kbscan()!=KEY_NONE)

;//死循环等待

这样很糟糕,如果把键盘按下一直不放,这将导致整个系统其它的任务也不能执行,这将是个很严重的bug。

有人会这样进行处理:

While(kbsan()!=KEY_NONE)

{

Delay(10);

If(Num++>10)

Break;

}

即在一定得时间内,如果键盘一直按下,将作为有效键处理。这样虽然不导致整个系统其它任务不能运行,但也很大程度上,削弱了系统的实时性能,因为他用了延时函数;

我们用两种有效的方法来解决此问题:

1在按键功能比较简单的情况下,我们仍然用上面的kbscan()函数进行扫描,只是把其中去抖用的软件延时去了,把去抖以及判断按键的释放用一个函数来处理,它不用软件延时,而是用定时器的计时(用一般的计时也行)来完成;代码如下

void ClearKeyFlag(void)

{

KeyDebounceFlg=0;

KeyReleaseFlg=0;

}

void ScanKey(void)

{

++KeyDebounceCnt;//去抖计时(这个计时也可以放在后台定时器计时函数中处理)

KeyCode=kbscan();

if(KeyCode!=KEY_NONE)

{

if(KeyDebounceFlg)//进入去抖状态的标志位

{

if(KeyDebounceCnt>DEBOUNCE_TIME)//大于了去抖规定的时间

{

if(KeyCode==KeyOldCode)//按键依然存在,则返回键值

{

KeyDebounceFlg=0;

KeyReleaseFlg=1;//释放标志

return;//Here exit with keycode

}

ClearKeyFlag();//KeyCode!=KeyOldCode,只是抖动而已

}

}else{

if(KeyReleaseFlg==0)

{

KeyOldCode=KeyCode;

KeyDebounceFlg=1;

KeyDebounceCnt=0;

}else{

if(KeyCode!=KeyOldCode)

ClearKeyFlag();

}

}

}else{

ClearKeyFlag();//没有按键则清零标志

}

KeyCode=KEY_NONE;

}

在按键情况较复杂的情况,如有长按键,组合键,连键等一些复杂功能的按键时候,我们跟倾向于用状态机来实现键盘的扫描;

//avr单片机中4*3扫描状态机实现

char read_keyboard_FUN2()

{

static char key_state=0,key_value,key_line,key_time; char key_return=No_key,i;

switch(key_state)

{

case0://最初的状态,进行3*4的键盘扫描

key_line=0b00001000;

for(i=1;i<=4;i++)//扫描键盘

{

PORTD=~key_line;//输出行线电平

PORTD=~key_line;//必须送2次!!!(注1)

key_value=Key_mask&PIND;//读列电平

if(key_value==Key_mask)

key_line<<=1;//没有按键,继续扫描

else

{

key_state++;//有按键,停止扫描

break;//转消抖确认状态

}

}

break;

case1://此状态来判断按键是不是抖动引起的

if(key_value==(Key_mask&PIND))//再次读列电平,

{

key_state++;//转入等待按键释放状态

key_time=0;

}

else

key_state--;//两次列电平不同返回状态0,(消抖处理)break;

case2://等待按键释放状态

PORTD=0b00000111;//行线全部输出低电平

PORTD=0b00000111;//重复送一次

if((Key_mask&PIND)==Key_mask)

{

key_state=0;//列线全部为高电平返回状态0

key_return=(key_line|key_value);//获得了键值

}

else if(++key_time>=100)//如果长时间没有释放

{

key_time=0;

key_state=3;//进入连键状态

key_return=(key_line|key_value);

}

break;

case3://对于连键,每隔50ms就得到一次键值,windows xp系统就是这样做的

PORTD=0b00000111;//行线全部输出低电平

PORTD=0b00000111;//重复送一次

if((Key_mask&PIND)==Key_mask)

key_state=0;//列线全部为高电平返回状态0

else if(++key_time>=5)//每隔50MS为一次连击的按键

{

key_time=0;

key_return=(key_line|key_value);

}

break;

}

return key_return;

}

以上用了4个状态,一般的键盘扫描只用前面3个状态就可以了,后面一个状态是为增加“连键”功能设计的。连键——即如果按下某个键不放,则迅速的多次响应该键值,直到其释放。在主循环中每隔10ms让该键盘扫描函数执行一次即可;我们定其时限为10ms,当然要求并不严格。

2数码管的显示

一般情况下我们用的八位一体的数码管,采用动态扫描的方法来完成显示;非常庆幸人眼在高于50hz以上的闪烁时发现不了的。所以我们在动态扫描数码管的间隔时间是充裕的。这里我们定其时限为4ms(250HZ),用定时器定时为2ms,在定时中断程序中进行扫描的显示,每次只显示其中的一位;当然时限也可以弄长一些,更推荐的方法是把显示函数放入主循环中,而定时中断中置位相应的标志位即可;

//Timer0比较匹配中断服务,4ms定时

interrupt[TIM0_COMP]void timer0_comp_isr(void)

{

display();//调用LED扫描显示

……………………

}

void display(void)//8位LED数码管动态扫描函数

{

PORTC=0xff;//这里把段选都关闭是很必要的,否则数码管会产生拖影PORTA=led_7[dis_buff[posit]];

PORTC=position[posit];

if(++posit>=8)

posit=0;

}

3串口接收数据帧

串口接收时用中断方式的,这无可厚非。但如果你试图在中断服务程序中完成一帧数据的接收就麻烦大了。永远记住,中断服务函数越短越好,否则影响这个程序的实时性能。一个数据帧一般包括若干个字节,我们需要判断一帧是否完成,校验是否正确。在这个过程中我们不能用软件延时,更不能用死循环等待等方式;

所以我们在串口接收中断函数中,只是把数据放置于一个缓冲队列中。

至于组成帧,以及检查帧的工作我们在主循环中解决,并且每次循环中我们只处理一个数据,每个字节数据的处理间隔的弹性比较大,因为我们已经缓存在了队列里面。

/*==========================================

功能:串口发送接收的时间事件

说明:放在大循环中每10ms一次

输出:none

输入:none

==========================================*/

void UARTimeEvent(void)

{

if(TxTimer!=0)//发送需要等待的时间递减

--TxTimer;

if(++RxTimer>RX_FRAME_RESET)//

RxCnt=0;//如果接受超时(即不完整的帧或者接收一帧完成),把接收的不完整帧覆盖

}

/*==========================================

功能:串口接收中断

说明:接收一个数据,存入缓存

输出:none

输入:none

==========================================*/

interrupt[USART_RXC]void uart_rx_isr(void)

{

INT8U status,data;

status=UCSRA;

data=UDR;

if((status&(FRAMING_ERROR|PARITY_ERROR|DATA_OVERRUN))==0){ RxBuf[RxBufWrIdx]=data;

if(++RxBufWrIdx==RX_BUFFER_SIZE)//接收数据于缓冲中

RxBufWrIdx=0;

if(++RxBufCnt==RX_BUFFER_SIZE){

RxBufCnt=0;

//RxBufferOvf=1;

}

}

}

/*==========================================

功能:串口接收数据帧

说明:当非0输出时,收到一帧数据

放在大循环中执行

输出:==0:没有数据帧

!=0:数据帧命令字

输入:none

==========================================*/

INT8U ChkRxFrame(void)

{

INT8U dat;

INT8U cnt;

INT8U sum;

INT8U ret;

ret=RX_NULL;

if(RxBufCnt!=0){

RxTimer=0;//清接收计数时间,UARTimeEvent()中对于接收超时做了放弃整帧数据的处理

//Display();

cnt=RxCnt;

dat=RxBuf[RxBufRdIdx];//Get Char

if(++RxBufRdIdx==RX_BUFFER_SIZE)

RxBufRdIdx=0;

Cli();

--RxBufCnt;

Sei();

FrameBuf[cnt++]=dat;

if(cnt>=FRAME_LEN)//组成一帧

{

sum=0;

for(cnt=0;cnt<(FRAME_LEN-1);cnt++)

sum+=FrameBuf[cnt];

if(sum==dat)

ret=FrameBuf[0];

cnt=0;

}

RxCnt=cnt;

}

return ret;

}

以上的代码ChkRxFrame()可以放于串口接收数据处理函数RxProcess()中,然后放入主循环中执行即可。以上用一个计时变量RxTimer,很微妙的解决了接收帧超时的放弃帧处理,它没有用任何等待,而且主循环中每次只是接收一个字节数据,时间很短。

我们开始架构整个系统的框架:

我们选用一个系统不常用的TIMER来产生系统所需的系统基准节拍,这里我们选用4ms;

在meg8中我们代码如下:

//Timer0overflow interrupt service routine

interrupt[TIM0_OVF]void timer0_ovf_isr(void)

{

//Reinitialize Timer0value

TCNT0=0x83;

//Place your code here

if((++Time1ms&0x03)==0)

TimeIntFlg=1;

}

然后我们设计一个TimeEvent()函数,来调用一些在以指定的频率需要循环调用

的函数,

比如每个4ms我们就进行喂狗以及数码管动态扫描显示,每隔1s我们就调用led 闪烁程序,每隔20ms我们进行键盘扫描程序;

void TimeEvent(void)

{

if(TimeIntFlg){

TimeIntFlg=0;

ClearWatchDog();

display();//在4ms事件中,调用LED扫描显示,以及喂狗

if(++Time4ms>5){

Time4ms=0;

TimeEvent20ms();//在20ms事件中,我们处理键盘扫描read_keyboard_FUN2()

if(++Time100ms>10){

Time100ms=0;

TimeEvent1Hz();//在1s事件中,我们使工作指示灯闪烁

}

}

UARTimeEvent();//串口的数据接收事件,在4ms事件中处理

}

}

显然整个思路已经很清晰了,cpu需要处理的循环事件都可以根据其对于时间的要求很方便的加入该函数中。但是我们对这事件有要求:

执行速度快,简短,不能有太长的延时等待,其所有事件一次执行时间和必须小于系统的基准时间片4ms(根据需要可以加大系统基准节拍)。所以我们的键盘扫描程序,数码管显示程序,串口接收程序都如我先前所示。如果逼不得已需要用到较长的延时(如模拟IIc时序中用到的延时)

我们设计了这样的延时函数:

void RunTime250Hz(INT8U delay)//此延时函数的单位为4ms(系统基准节拍) {

while(delay){

if(TimeIntFlg){

--delay;

TimeEvent();

}

TxProcess();

RxProcess();

}

}

我们需要延时的时间=delay*系统记住节拍4ms,此函数就确保了在延时的同时,

我们其它事件(键盘扫描,led显示等)也并没有被耽误;

好了这样我们的主函数main()将很简短:

Void main(voie)

{

Init_all();

while(1)

{

TimeEvent();//对于循环事件的处理

RxProcess();//串口对接收的数据处理

TxProcess();//串口发送数据处理

}

}

整体看来我们的系统就成了将近一个万能的模版了,根据自己所选的cpu,选个定时器,在添加自己的事件函数即可,非常灵活方便实用,一般的单片机能胜任的场合,该模版都能搞定。

整个系统以全局标志作为主线,形散神不散;系统耗费比较小,只是牺牲了一个Timer而已,在资源缺乏的单片机中,非常适;曾经看过一个网友的模版“单片机实用系统”,其以51为例子写的,整体思路和这个差不多,不过他写得更为规范紧凑,非常欣赏;但个人觉得代码开销量要大些,用惯了都一样哦。但是由于本系统以全局标志为驱动事件,所以比较感觉比较凌乱,全局最好都做好注释,而其要注意一些隐形的函数递归情况,千万不要递归的太深哦(有的单片机不支持)。

51单片机常用子程序汇总

目录 1、通过串口连续发送n个字节的数据 /*************************************************************** 模块功能:通过串口连续发送n个字节的数据 参数说明: s:待发送数据的首地址 n:要发送数据的字节数 ***************************************************************/ void SendD(unsigned char *s,unsigned char n) { unsigned char unX; if(n>0) { ES=0; // 关闭串口中断 for(unX=0;unX #include #define Nop() _nop_() //空指令

sbit SDA=P1^3; sbit SCL=P1^2; bit ACK; void Start_I2c() { SDA=1; Nop(); SCL=1; Nop(); Nop(); Nop(); Nop(); Nop(); SDA=0; Nop(); Nop(); Nop(); Nop(); Nop(); SCL=0; //钳住I2C总线,准备发送或接受数据Nop(); Nop(); } (2)结束总线函数 /*************************************************************** 模块功能:发送I2C总线结束条件 ***************************************************************/ void Stop_I2c() { SDA=0; Nop(); SCL=1; Nop(); Nop(); Nop(); Nop(); Nop(); SDA=1; Nop(); Nop(); Nop(); Nop();

51单片机汇编程序范例

16位二进制数转换成BCD码的的快速算法-51单片机2010-02-18 00:43在做而论道上篇博文中,回答了一个16位二进制数转换成BCD码的问题,给出了一个网上广泛流传的经典转换程序。 程序可见: http: 32.html中的HEX2BCD子程序。 .说它经典,不仅是因为它已经流传已久,重要的是它的编程思路十分清晰,十分易于延伸推广。做而论道曾经利用它的思路,很容易的编写出了48位二进制数变换成16位BCD码的程序。 但是这个程序有个明显的缺点,就是执行时间太长,转换16位二进制数,就必须循环16遍,转换48位二进制数,就必须循环48遍。 上述的HEX2BCD子程序,虽然长度仅仅为26字节,执行时间却要用331个机器周期。.单片机系统多半是用于各种类型的控制场合,很多时候都是需要“争分夺秒”的,在低功耗系统设计中,也必须考虑因为运算时间长而增加系统耗电量的问题。 为了提高整机运行的速度,在多年前,做而论道就另外编写了一个转换程序,程序的长度为81字节,执行时间是81个机器周期,(这两个数字怎么这么巧!)执行时间仅仅是经典程序的!.近来,在网上发现了一个链接: ,也对这个经典转换程序进行了改进,话是说了不少,只是没有实质性的东西。这篇文章提到的程序,一直也没有找到,也难辩真假。 这篇文章好像是选自某个著名杂志,但是在术语的使用上,有着明显的漏洞,不像是专业人员的手笔。比如说文中提到的:

“使用51条指令代码,但执行这段程序却要耗费312个指令周期”,就是败笔。51条指令代码,真不知道说的是什么,指令周期是因各种机型和指令而异的,也不能表示确切的时间。 .下面说说做而论道的编程思路。;----------------------------------------------------------------------- ;已知16位二进制整数n以b15~b0表示,取值范围为0~65535。 ;那么可以写成: ; n = [b15 ~ b0] ;把16位数分解成高8位、低8位来写,也是常见的形式: ; n = [b15~b8] * 256 + [b7~b0] ;那么,写成下列形式,也就可以理解了: ; n = [b15~b12] * 4096 + [b11~b0] ;式中高4位[b15~b12]取值范围为0~15,代表了4096的个数; ;上式可以变形为: ; n = [b15~b12] * 4000 + {[b15~b12] * (100 - 4) + [b11~b0]} ;用x代表[b15~b12],有: ; n =x * 4000 + {x * (100 - 4) + [b11~b0]} ;即: ; n =4*x (千位) + x (百位) + [b11~b0] - 4*x ;写到这里,就可以看出一点BCD码变换的意思来了。 ;;上式中后面的位:

汇编51单片机考试常见试题

一、填空题 1.单片机是把中央处理器、存储器、定时器/计数器以及I/O接口电路等主要计算机部件集成在一块集成电路芯片上的微型计算机。 2.除了单片机这一名称之外,单片机还可称为微控制器、嵌入式控制器。 3.计算机的系统总线有地址总线、控制总线和数据总线。 4.80C51单片机基本型内部RAM有 128 个字节单元,这些单元可以分为三个用途不同的区域,一是工作寄存器区、二是位寻址区、三是数据缓冲区。5.8051单片机有2 个16位定时/计数器。 6.单片机存储器的主要功能是存储程序和数据。80C51含4 KB掩膜ROM。7.80C51在物理上有4个独立的存储器空间。 8.通常、单片机上电复位时PC= 0000H,SP= 07H;而工作寄存器则缺省采用第00 组,这组寄存器的地址范围是从00H~ 07H。 9.8051的堆栈是向地址的高端生成的。入栈时SP先加1,再压入数据。10.使用8031芯片时,需将/EA引脚接低电平,因为其片内无程序存储器。11.MCS-51特殊功能寄存器只能采用直接寻址方式。 12.汇编语言中可以使用伪指令,它们不是真正的指令,只是用来对汇编过程进行某种控制。 13.半导体存储器的最重要的两个指标是存储容量和存储速度。 14.当PSW4=1,PSW3=0时,工作寄存器Rn,工作在第2组。 15.在8051单片机中,由 2 个振荡(晶振)周期组成1个状态(时钟)周期,由 6个状态周期组成1个机器周期。 16.假定累加器A的内容30H,执行指令:1000H:MOVC A,@A+PC后,把程序存储器1031H单元的内容送累加器A中。 17.MCS-51单片机访问外部存储器时,利用ALE信号锁存来自P0口的低8位地址信号。 18.内部RAM中,位地址为30H的位,该位所在字节的字节地址为26H。 19.若A中的内容为63H,那么,P标志位的值为0。 20.在基址加变址寻址方式中,以累加器A作变址寄存器,以DPTR或PC作基址寄存器。 21.指令格式是由操作码和操作数所组成,也可能仅由操作码组成。 22.通过堆栈操作实现子程序调用,首先就要把PC的内容入栈,以进行断点保护。调用返回时,再进行出栈保护,把保护的断点送回到PC。 23.MCS-51单片机程序存储器的寻址范围是由程序计数器PC的位数所决定的,因为MCS-51的PC是16位的,因此其寻址的范围为64KB。 24.在寄存器间接寻址方式中,其“间接”体现在指令中寄存器的内容不是操作数,而是操作数的地址。 25.假定累加器A中的内容为30H,执行指令1000H:MOVC A,@A+PC 后,把程序存储器1031H单元的内容送入累加器A中。 26.12根地址线可寻址4 KB存储单元。 27.:假定A=55H,R3=0AAH,在执行指令ANL A,R3后,A=00H,R3=0AAH。28.MCS-51的P0口作为输出端口时,每位能驱动8个LSTTL负载。 29.MCS-51有4个并行I/O口,其中P1~P3是准双向口,所以由输出转输入时必须先写入“1”。 30.MCS-51的堆栈是软件填写堆栈指针临时在片内数据存储器内开辟的区域。

单片机的各种程序

单片机的各种程序 1. 八个灯循环点亮 ORG 0030H START:MOV SP,#5FH MOV R2,#08H MOV A,#0FEH NEXT:MOV P1,A ACALL DELAY RL A DJNZ R2,NEXT MOV R2,#08H MOV A,#7FH NEXT1:MOV P1,A ACALL DELAY RR A DJNZ R2,NEXT1 SJMP START DELAY:MOV R3,#0FFH DEL1:MOV R4,#0FFH DJNZ R4,$ DJNZ R3,DEL1 RET END 2. 查表的例子 org 0000h start: mov dptr,#ledtab movc a,@a+dptr mov p0,a sjmp start ledtab: db:0c0h,0f9h,04h,0b0h,99h,92h,82h,0f8h,80h end https://www.360docs.net/doc/8d10408477.html, 0000H MOV A,#0FEH SHIFT: LCALL FLASH

RL A SJMP SHIFT FLASH: MOV R2,0AH FLASH1:MOV P1,A LCALL DELAY MOV P1,#0FFH LCALL DELAY DJNZ R2,FLASH1 RET DELAY:MOV R5,#200 D1:MOV R6,#123 NOP DJNZ R6,$ DJNZ R5,D1 RET 4.数码显示管显示2015循环 org 0000h start: loop: mov p1,#0c0h lcall DELAY mov p1,#0f9h lcall DELAY mov p1,#0a4h lcall DELAY mov p1,#0b0h lcall DELAY mov p1,#99h lcall DELAY mov p1,#92h lcall DELAY mov p1,#82h lcall DELAY mov p1,#0f8h lcall DELAY mov p1,#80h lcall DELAY

单片机串口通信C程序及应用实例

一、程序代码 #include//该头文件可到https://www.360docs.net/doc/8d10408477.html,网站下载#define uint unsigned int #define uchar unsigned char uchar indata[4]; uchar outdata[4]; uchar flag; static uchar temp1,temp2,temp3,temp; static uchar R_counter,T_counter; void system_initial(void); void initial_comm(void); void delay(uchar x); void uart_send(void); void read_Instatus(void); serial_contral(void); void main() { system_initial(); initial_comm(); while(1) { if(flag==1) { ES = 0; serial_contral(); ES = 1; flag = 0; } else read_Instatus(); } } void uart_send(void) { for(T_counter=0;T_counter<4;T_counter++) { SBUF = outdata[T_counter]; while(TI == 0);

TI = 0; } T_counter = 0; } uart_receive(void) interrupt 4 { if(RI) { RI = 0; indata[R_counter] = SBUF; R_counter++; if(R_counter>=4) { R_counter = 0; flag = 1; } } } void system_initial(void) { P1M1 = 0x00; P1M0 = 0xff; P1 = 0xff; //初始化为全部关闭 temp3 = 0x3f;//初始化temp3的值与六路输出的初始值保持一致 temp = 0xf0; R_counter = 0; T_counter = 0; } void initial_comm(void) { SCON = 0x50; //设定串行口工作方式:mode 1 ; 8-bit UART,enable ucvr TMOD = 0x21; //TIMER 1;mode 2 ;8-Bit Reload PCON = 0x80; //波特率不加倍SMOD = 1 TH1 = 0xfa; //baud: 9600;fosc = 11.0596 IE = 0x90; // enable serial interrupt TR1 = 1; // timer 1 RI = 0; TI = 0; ES = 1; EA = 1; }

最经典的51单片机经典流水灯汇编程序

单片机流水灯汇编程序设计 开发板上的8只LED为共阳极连接,即单片机输出端为低电平时即可点亮LED。 程序A: ;用最直接的方式实现流水灯 ORG 0000H START:MOV P1,#01111111B ;最下面的LED点亮 LCALL DELAY;延时1秒 MOV P1,#10111111B ;最下面第二个的LED点亮 LCALL DELAY;延时1秒 MOV P1,#11011111B ;最下面第三个的LED点亮(以下省略) LCALL DELAY MOV P1,#11101111B LCALL DELAY MOV P1,#11110111B LCALL DELAY MOV P1,#11111011B LCALL DELAY MOV P1,#11111101B LCALL DELAY MOV P1,#11111110B LCALL DELAY MOV P1,#11111111B ;完成第一次循环点亮,延时约0.25秒 AJMP START ;反复循环 ;延时子程序,12M晶振延时约250毫秒 DELAY: MOV R4,#2 L3: MOV R2 ,#250 L1: MOV R3 ,#250 L2: DJNZ R3 ,L2 DJNZ R2 ,L1 DJNZ R4 ,L3 RET END 程序B: ;用移位方式实现流水灯

ajmp main ;跳转到主程序 org 0030h ;主程序起始地址 main: mov a,#0feh ;给A赋值成11111110 loop: mov p1,a ;将A送到P1口,发光二极管低电平点亮 lcall delay ;调用延时子程序 rl a ;累加器A循环左移一位 ajmp loop ;重新送P1显示 delay: mov r3,#20 ;最外层循环二十次 d1: mov r4,#80 ;次外层循环八十次 d2: mov r5,#250 ;最内层循环250次 djnz r5,$ ;总共延时2us*250*80*20=0.8S djnz r4,d2 djnz r3,d1 ret end 51单片机经典流水灯程序,在51单片机的P2口接上8个发光二极管,产生流水灯的移动效果。 ORG 0 ;程序从0地址开始 START: MOV A,#0FEH ;让ACC的内容为11111110 LOOP: MOV P2,A ;让P2口输出ACC的内容 RR A ;让ACC的内容左移 CALL DELAY ;调用延时子程序 LJMP LOOP ;跳到LOOP处执行 ;0.1秒延时子程序(12MHz晶振)=================== DELAY: MOV R7,#200 ;R7寄存器加载200次数 D1: MOV R6,#250 ;R6寄存器加载250次数 DJNZ R6,$ ;本行执行R6次 DJNZ R7,D1 ;D1循环执行R7次 RET ;返回主程序

单片机 c语言程序框架详解

/*单片机avr 流水灯源程序文件名:led.c */ #include void delay(uint time_c) //子函数,实现延时功能,void 表示此函数无返回值,delay 函数名,time_c 函数的参数-无符号的整形数值 { int i,j; //变量声明 while(time_c--) { for (j=0;j<1200;j++) {; }; //函数体内的语句以';'分号结尾,表示一条语句的结束,分号需要用英文标点输入 } } void main (void) //主函数 { //程序的初始化 DDRA=0xFF; //DDRA -PA口的方向寄存器,1为输出,0为输入,PA的8个I/O口全部设为输出。 PORTA=0xFF; //PORTA -PA口的输出控制寄存器,1为输出高电平,0为输出低电平,此处,PA口全部输出高电平。 while(1) // 死循环 { PORTA=0xFE; //PA口的第0位清0,点亮第一个灯 delay(500); // 延时 PORTA=0xFD; //点亮第二个灯 delay(500); PORTA=0xFB; //点亮第三个灯 delay(500); PORTA=0xF7; //点亮第四个灯 dealy(500); PORTA=0xEF; //点亮第五个灯 dealy(500); PORTA=0xDF; //点亮第六个灯 dealy(500);

PORTA=0xBF; //点亮第七个灯 delay(500); PORTA=0x7F; //点亮第八个灯 delay(500); } } /* 流水灯程序结束*/ ------------------------------------------------------------------------------------------------------------------------------- #include :#include c语言的文件包含指令,指的是在一个文件中包含另一个文件的全部内容,在这个源文件led.c中包含了头文件’iom16v.h'的全部内容,(c语言中源文件的扩展名'.c',头文件的扩展名为'.h'),此处iom16v.h 头文件定义了单片机ATmega16的内部寄存器参数,使用不同的单片机要用不同的头文件,例如:使用ATmega32 ,头文件需改为'iom32v.h' 。 中“<>"表示在系统默认的目录中搜索文件,若为"iom16v.h" 双引号表示在项目源文件所在的目录搜索文件。 void delay(unit time_c) { } ;为自定义的子函数,实现某一特定功能的函数,c语言函数的内容都放在{}中;delay(500)为子函数调用,实现延时功能,500为函数的实参,time_c 称为形式参数,单片机的运行速度非常快,如果不加延时,所有的灯看起来都是亮的,人眼无法分辨,可以增加,或减少延时的时间看看结果的变化。 void main(void) { .............. while(1) { .........}; } main 为主函数,是每一个c语言程序中必须有的,也必须只能有一个。它是单片机程序运行开始的入口处,在main函数中都有一个while(1)死循环,程序将在while所包含的语句中周而复始的运行。 /*单片机avr 流水灯源程序文件名:led.c */ 在c语言中在 '/* 和 '*/' 之间的内容为程序的注释,方便程序的阅读,可以对多行进行注释,'//':只能进行单行注释。 常量:在程序运行过程中数值不变的数据。 变量:在程序运行过程中,其值可以改变的数据 在书写变量说明时,应注意以下几点: 1.允许在一个类型说明符后,说明多个相同类型的变量。各变量名之间用逗号间隔。类型说明符与变量名之间至少用一个空格间隔。 2.最后一个变量名之后必须以“;”号结尾。 3.变量说明必须放在变量使用之前。一般放在函数体的开头部分。

单片机C语言编程实例

单片机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版软件,基本可以满足一般的个

51单片机考试常见试题简答 题

简答题部分 1、什么叫堆栈? 答:堆栈是在片内RAM中专门开辟出来的一个区域,数据的存取是以"后进先出"的结构方式处理的。实质上,堆栈就是一个按照"后进先出"原则组织的一段内存区域。 2、进位和溢出? 答:两数运算的结果若没有超出字长的表示范围,则由此产生的进位是自然进位;若两数的运算结果超出了字长的表示范围(即结果不合理),则称为溢出。 3、在单片机中,片内ROM的配置有几种形式?各有什么特点? 答:单片机片内程序存储器的配置形式主要有以下几种形式:(1)掩膜(Msak)ROM型单片机:内部具有工厂掩膜编程的ROM,ROM中的程序只能由单片机制造厂家用掩膜工艺固 化,用户不能修改ROM中的程序。掩膜ROM单片机适合于 大批量生产的产品。用户可委托芯片生产厂家采用掩膜方法 将程序制作在芯片的ROM。 (2)EPROM型单片机:内部具有紫外线可擦除电可编程的只读存储器,用户可以自行将程序写入到芯片内部的EPROM 中,也可以将EPROM中的信息全部擦除。擦去信息的芯片 还可以再次写入新的程序,允许反复改写。 (3)无ROM型单片机:内部没有程序存储器,它必须连接程序存储器才能组成完整的应用系统。 无ROM型单片机价格低廉,用户可根据程序的大小来选择外接 程序存储器的容量。这种单片机扩展灵活,但系统结构较复 杂。 (4)E2ROM型单片机:内部具有电可擦除叫可编程的程序存储器,使用更为方便。该类型目前比较常用 (5) OTP(One Time Programmable)ROM单片机:内部具有一次可编程的程序存储器,用户可以在编程器上将程序写入片 内程序存储器中,程序写入后不能再改写。这种芯片的价 格也较低。 4、什么是单片机的机器周期、状态周期、振荡周期和指令周期?它们之间是什么关系? 答:某条指令的执行周期由若干个机器周期(简称M周期)构成,一个机器周期包含6个状态周期(又称时钟周期,简称S周期),而一个状态周期又包含两个振荡周期(P1和P2,简称P周期)。也就是说,指令执行周期有长有短,但一个机器周期恒等于6个状态周期或12个振荡周

51单片机实例(含详细代码说明)

1.闪烁灯 1.实验任务 如图4.1.1所示:在P1.0端口上接一个发光二极管L1,使L1在不停地一亮一灭,一亮一灭的时间间隔为0.2秒。 2.电路原理图 图4.1.1 3.系统板上硬件连线 把“单片机系统”区域中的P1.0端口用导线连接到“八路发光二极管指示模块”区域中的L1端口上。 4.程序设计内容 (1).延时程序的设计方法 作为单片机的指令的执行的时间是很短,数量大微秒级,因此,我们要 求的闪烁时间间隔为0.2秒,相对于微秒来说,相差太大,所以我们在 执行某一指令时,插入延时程序,来达到我们的要求,但这样的延时程 序是如何设计呢?下面具体介绍其原理:

如图4.1.1所示的石英晶体为12MHz,因此,1个机器周期为1微秒机器周期微秒 MOV R6,#20 2个 2 D1: MOV R7,#248 2个 2 2+2×248=498 20× DJNZ R7,$ 2个2×248 (498 DJNZ R6,D1 2个2×20=40 10002 因此,上面的延时程序时间为10.002ms。 由以上可知,当R6=10、R7=248时,延时5ms,R6=20、R7=248时, 延时10ms,以此为基本的计时单位。如本实验要求0.2秒=200ms, 10ms×R5=200ms,则R5=20,延时子程序如下: DELAY: MOV R5,#20 D1: MOV R6,#20 D2: MOV R7,#248 DJNZ R7,$ DJNZ R6,D2 DJNZ R5,D1 RET (2).输出控制 如图1所示,当P1.0端口输出高电平,即P1.0=1时,根据发光二极管 的单向导电性可知,这时发光二极管L1熄灭;当P1.0端口输出低电平, 即P1.0=0时,发光二极管L1亮;我们可以使用SETB P1.0指令使P1.0 端口输出高电平,使用CLR P1.0指令使P1.0端口输出低电平。 5.程序框图 如图4.1.2所示

基于51单片机的音乐程序

基于51单片机的按键切换播放音乐 原理图: 引脚说明:共5个按键,分别接51单片机的P0~P4引脚,前4个按键控制播放设置好的四首音乐,第5个按键用来关闭音乐。按键采用中断方式,任意时刻按下任意按键则立即进入所按按键的功能;蜂鸣器接单片机的P3.6口。 仿真说明:使用proteus仿真,晶振:12MHZ。 程序代码如下: /*12Mhz晶振工作*/ #include #define uint unsigned int #define uchar unsigned char sbit voice=P3^6; uchar code sound1[]={0xff, 0x40,0x80,0x30,0x40,0x2b,0x40,0x26,0x80,0x24,0x10,0x26,0x40,0x30,0x40, 0x2b,0x80,0x30,0x40,0x39,0x40,0x30,0xc0,0x40,0x80,0x30,0x40,0x2b,0x40, 0x26,0x40,0x26,0x20,0x24,0x20,0x20,0x40,0x30,0x40,0x24,0x80,0x26,0x10,

0x20,0x40,0x19,0x40,0x19,0x80,0x1c,0x10,0x1c,0x80,0x20,0x40,0x20,0x20, 0x1c,0x20,0x19,0x40,0x1c,0x20,0x20,0x20,0x26,0xc0,0x24,0x80,0x24,0x10, 0x20,0x40,0x1c,0x40,0x20,0x40,0x24,0x20,0x26,0x20,0x2b,0x80,0x33,0x40, 0x33,0x20,0x39,0x20,0x40,0x40,0x39,0x40,0x30,0xc0,0x18,0x80,0x1c,0x80, 0x24,0x80,0x20,0x10,0x1c,0x80,0x19,0x40,0x19,0x20,0x19,0x20,0x19,0x40, 0x1c,0x20,0x20,0x20,0x26,0xc0,0x18,0x80,0x1c,0x80,0x24,0x80,0x20,0x10, 0x1c,0x80,0x1c,0x40,0x1c,0x20,0x1c,0x20,0x1c,0x40,0x24,0x20,0x26,0x20, 0xff,0x20,0x00};//同一首歌*/ uchar code sound2[]={0xff, 0x18,0x40,0x1c,0x20,0x18,0x20,0x13,0x40,0x13,0x20,0x15,0x20,0x13,0x20, 0x15,0x20,0x13,0x20,0x15,0x20,0x18,0x20,0x19,0x20,0x1c,0x20,0x20,0x20, 0x1c,0x40,0x19,0x20,0x18,0x20,0x15,0x40,0x10,0x80, 0x13,0x10,0x10,0x40,0x15,0x10,0x13,0x10,0x18,0x10,0x1c,0x10,0x26,0x10, 0x13,0x10,0x18,0x10,0x1c,0x10,0x26,0x10,0x13,0x10,0x18,0x10,0x1c,0x10, 0x26,0x10,0x13,0x10,0x18,0x10,0x1c,0x10,0x26,0x10,0x15,0x10,0x19,0x10, 0x20,0x10,0x2b,0x10,0x15,0x10,0x19,0x10,0x20,0x10,0x2b,0x10,0x15,0x10, 0x19,0x10,0x20,0x10,0x2b,0x10,0x15,0x10,0x19,0x10,0x20,0x10,0x2b,0x10, 0x18,0x10,0x1c,0x10,0x24,0x10,0x30,0x10,0x18,0x10,0x1c,0x10,0x24,0x10, 0x30,0x10,0x19,0x10,0x20,0x10,0x2b,0x10,0x19,0x10,0x19,0x10,0x20,0x10, 0x2b,0x10,0x19,0x10,0x18,0xc0,0xff,0x40,0x40,0x10,0x39,0x20,0x30,0x20, 0x2b,0x20,0x30,0x20,0x2b,0x20,0x26,0x20,0x26,0x20,0x26,0x20,0x26,0x20, 0x26,0x20,0x2b,0x20,0x30,0x20,0x2b,0x20,0x26,0x20,0x26,0x20,0x26,0x20, 0x26,0x20,0x26,0x20,0x2b,0x20,0x30,0x20,0x2b,0x40,0x30,0x10,0x30,0x20, 0x39,0x20,0x30,0x40,0x2b,0x10,0x2b,0x20,0x26,0x20,0x26,0x80,0x40,0x10, 0x39,0x20,0x30,0x20,0x2b,0x20,0x30,0x20,0x2b,0x20,0x30,0x20,0x30,0x20, 0x20,0x20,0x20,0x20,0x26,0x20,0x2b,0x20,0x26,0x20,0x2b,0x20,0x30,0x20, 0x30,0x20,0x26,0x20,0x26,0x20,0x26,0x20,0x2b,0x20,0x30,0x20,0x2b,0x40, 0x2b,0x10,0x2b,0x20,0x2b,0x20,0x2b,0x40,0x30,0x10,0x30,0x20,0x39,0x20,

51单片机常见汇编程序实验代码

1. 将片外8000H-80FFH单元写入数据AB (1) 2. 将片内RAM20H单元中数据在数码管 上显示出来 (1) 3. 将片内ARM30H-40H单元清零 (2) 4. 将六位数显示在数码管上 (2) 5. 8255并口芯片的应用:交通灯控制系统 的设计 (3) 6. 将交通灯点亮 (3) 7. AD转换实验 (4) 8. DA转换实验 (5) 9. 定时器的应用 (5) 10. 开关控制LED的亮灭及速度 (6) 11. 计数器实验 (6) 12. 串并转换实验 (7) 13. 直流电机速度检测 (7) 14. 8255PB外接8个开关,编程将开关状 态显示在数码管上(串并转换动态扫描方式) (8) 15. P3.4接开关K,编程将开关拨动次数, 通过串并转换的方式进行显示 (9) 16. 比较片内RAM30H、31H两个单元值 的大小,将较大的数显示在数码管上· 10 17. 单片机P1口接8个开关,编程将开关 状态显示在数码管上(串并转换动态扫描 方式) (10) 18. 将片内50H单元的值显示在数码管上11 19. 开关K1接P1.0,K2接P1.1,编程实 现当按下K1时在数码管上显示50H单元 的值,按下K2在数码管上显示51H单元 的值 (12) 1. 将片外8000H-80FFH单元写入数据AB ORG 0000H ;程序从0000H开始执行 AJMP MAIN ;跳转到主程序 ORG 0030H ;以免覆盖中断地址 MAIN: MOV SP,#60H; 避免堆栈和工作寄存 器区冲突 MOV DPTR,#8000H MOV R0,#0 LOOP: MOV A,#0ABH MOVX @DPTR,A INC DPTR INC R0 CJNE R0,#0,LOOP ; 判断 AJMP $; 等待 END ;调试-视图-M存储器(输入地址X:8000H) 2. 将片内RAM20H单元中数据在数码管上显示 出来 ORG 0000H ;程序从0000H开始执行 AJMP MAIN ;跳转到主程序 ORG 0030H ;以免覆盖中断地址 MAIN: MOV SP,#60H ;避免堆栈和工作寄存器区冲突 MOV DPTR,#0E100H ;指向命令口地址 MOV A,#03H ;PA、PB口输出 MOVX @DPTR,A ;所有并口显示程序先进行8155初始化 MOV 20H,#34H MOV A,20H ACALL CHAI LOOP: MOV R0,#10H ;第一个显示数的地址送R0 MOV R1,#2 ;显示2个数 MOV R2,#1 ;从倒数第一个数码管开始显示 ACALL DISPLAY LJMP LOOP ;判断 CHAI: MOV B,#10H DIV AB MOV 10H,B MOV 11H,A RET DISPLAY: MOV A,@R0 MOV 0FH,#8 ACALL P164 ACALL PBIT ACALL DELAY MOV A,#0 MOVX @DPTR,A INC R0 DJNZ R1,DISPLAY

51单片机基础C程序架构

51单片机基础C程序架构 作者:u010785142 keil基本步骤: (1)新建一个工程:Project——New uVision Project (2)选择型号:AT89C52 (3)新建.c文件:File——new——a.c 保存为:.c后缀 (4)添加.c文件: (5)编写程序 以下是基本程序架构:很重要的笔记 A. 基本程序框架:(点亮小灯) #include sbit LED=P1^0; void main (void) { LED=0; // P1 = 0xfe; while (1) { //空循环 } } B. for循环语句:(小灯循环点亮) unsigned char i; for(i=0;i<10;i++) {;} 执行顺序:i=0; —— i<10; —— {}中的内容—— i++ ——。。。 C. 左移/右移(小灯逐个往左/右移动亮) P1=0xfe; // P1=0x7f; for(i=0;i<8;i++) //加入for循环,表明for循环大括号中的程序循环执行8次 { Delay(50000); P1<<=1; //P1>>=1; } 循环左移/右移: for(i=0;i<8;i++) //加入for循环,表明for循环大括号中的程序循环执行8次 { Delay(50000); P1<<=1; //P1>>=1; P1=P1|0x01; //P1=P1|0x80;

//左移后,最右端自动赋值0,所以需要该语句赋值1 } P1=0xfe; //P1=0x7f; //重新赋初始值 D. 数组的使用: unsigned char code table[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe, 0xff,0xff,0x00,0x00, 0x55,0x55,0xaa,0xaa}; for(i=0;i<16;i++) { P1=table[i]; Delay(3000); } E. PWM调光 sbit LED0=P1^0; void main (void) { unsigned int CYCLE=600,PWM_LOW=0; while(1) { LED0=1; Delay(6000); for(PWM_LOW=1;PWM_LOW0;PWM_LOW--) { LED0=0; Delay(PWM_LOW); LED0=1; Delay(CYCLE-PWM_LOW); } } F. 共阳数码管显示(循环显示数字) unsignedchar code dofly_table[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,};

单片机汇编程序实例

单片机程序入门小例子(汇编语言) 声明:以下3个例子都是正确的,都已经验证过。希望能给刚刚学习单片机的人一点参考。 编写人:大连民族学院自动化专业 例1:流水灯(加按键) ORG 0000H KEY1:MOV A,#0FEH CLR C LOOP1:MOV P2,A RLC A ACALL DELAY JNB P3.7,KEY2 LJMP LOOP1 KEY2:MOV A,#0FEH LOOP2:MOV P2,A RL A ACALL DELAY JNB P3.6,KEY1 LJMP LOOP2

DELAY:MOV R7,#20 D1:MOV R6,#200 D2:MOV R5,#123 NOP DJNZ R5,$ DJNZ R6,D2 DJNZ R7,D1 RET END 例2:数码管动态显示 ORG 0000H AJMP MAIN ORG 0003H AJMP PINT0 ORG 0100H MAIN:MOV SP,#40H CLR IT0 SETB EX0 SETB EA HERE:MOV 30H,#00H MOV 31H,#01H

MOV 32H,#02H MOV 33H,#03H LOOP:MOV R0,#30H MOV R1,#4 MOV R3,#0FEH MOV DPTR,#TAB LOOP1:MOV A,@R0 MOVC A,@A+DPTR MOV P0,A MOV P1,R3 LCALL DELAY INC R0 MOV A,R3 RL A MOV R3,A DJNZ R1,LOOP1 SJMP LOOP TAB:DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H DELAY:MOV R6,#6 LD:ACALL DELAY1 DJNZ R6,LD DELAY1:MOV R7,#124

51单片机常见程序,附带注释

51 单片机常见程序 附带注释 三位数分离成3个一位数,截取 bai=num/100;//输出百位数 shi=num%100/10;//输出十位数 ge=num/10;//输出个位数 #include //跑马灯程序。当时间约为20ms,形成动态扫描,看上去全亮。 #include #define uint unsigned int //无符号整型,占16位数,表示围0~65536 #define uchar unsigned char //无符号字符型占八位数,表示围0~255 void delayms(uint); uchar aa; //定义变量 void main() { aa=0xfe; while(1) { P2=aa; //控制单片机接口p2,循环亮 delayms(500); //当500换成5,看起来全亮,实际上灯一直亮灭,原因是视觉延迟 aa=_crol_(aa, 1); } } void delayms(uint xms) //子程序,延时,通过数数

{ uint i, j; for(i=xms;i>0;i--) for(j=110;j>0;j--); } #include //跑马灯程序。现在时间较长,多以是亮灭的流动,当时间约为20ms,形成动态扫描,看上去全亮。 #include #define uint unsigned int //无符号整型,占16位数,表示围0~65536 #define uchar unsigned char //无符号字符型占八位数,表示围0~255 void delayms(uint); uchar aa; //定义变量 void main() { aa=0xfe; while(1) { P2=aa; //控制单片机接口p2,循环亮 delayms(500); //当500换成5,看起来全亮,实际上灯一直亮灭,原因是视觉延迟 aa=_crol_(aa, 1); } }

单片机的一些常用程序

单片机复习程序1、从左到右的流水灯 /* 名称:从左到右的流水灯 说明:接在P0 口的8 个LED 从左到右循环依次点亮,产生走 马灯效果 */ #include #include #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); } } 2、交通灯 /* 名称:LED 模拟交通灯 说明:东西向绿灯亮若干秒,黄 灯闪烁5 次后红灯亮,红灯亮后,南北向由红灯变为绿灯,若干秒后南北 向黄灯闪烁5 此后变红灯,东西向变绿灯,如此重复。 */#include #define uchar unsigned char #define uint unsigned int sbit RED_A=P0^0; //东西向灯 sbit YELLOW_A=P0^1; sbit GREEN_A=P0^2;

sbit RED_B=P0^3; //南北向灯 sbit YELLOW_B=P0^4; sbit GREEN_B=P0^5; uchar Flash_Count=0,Operation_Type=1; //闪烁次数,操作类型变量 //延时 void DelayMS(uint x) { uchar i; while(x--) for(i=0;i<120;i++); } //交通灯切换 void Traffic_Light() { switch(Operation_Type) { case 1: //东西向绿灯与南北向红灯亮 RED_A=1;YELLOW_A=1;GREEN_A=0; RED_B=0;YELLOW_B=1;GREEN_B=1; DelayMS(2000); Operation_Type=2; break;

相关文档
最新文档