文章目录
前言一、Proteus仿真二、Keil代码编写1.流水灯2.来回点灯3.按键操作4.中断操作5.数码管6 动态数码管三、 练习题总结前言
本文用来记录博主学习单片机的过程与方法,希望对入门的同学有所帮助
该篇博客主要讲授如何基于proteus(仿真)+keil实现51单片机的点灯操作,本篇为入门篇,所以会介绍如何使用Proteus进行仿真,以及代码编写思路,实现简单的功能效果。
一、Proteus仿真
该软件的安装教程就不多赘述,网上资源很多,主要讲解满足51学习的使用,几个常用的功能。
在Proteus搭成这样即可完成本文章下除了5.数码管的其他所有的仿真任务。
1、常见原件库,按p键即可进行搜索,搜索指定元器件代号既可选入。
51单片机:AT89C52
排阻:RP1(主要用于P0口做串口使用的时候需要接上拉电阻)
LED:LED
按键:BUTTON
数码管:display
动态数码管:7SEG
2、电源、地等元件库。
二、Keil代码编写
1.流水灯
代码如下(示例):
#include <REGX52.H>void delay(void){unsigned int i = 40000; while(i--);}void main(void){unsigned char dat = 0x01, i=0;unsigned int direction = 0;//LED共阴,高电平点亮,设置0x01P1 = dat;//LED共阳,低电平点亮,设置0xfe,取反即可//P1 = ~data;while(1){if (direction == 0){P1 <<= 1;//P1+=1; //低电平点亮delay();if (P1 == 0x80){direction = 1;} }if (direction == 1){P1 >>= 1;//P1|=0x80;//低电平点亮delay();if (P1 == 0x01){direction = 0;}}}}
代码思路:
51单片机默认io口输出高电平,led灯采用的共阴极接法,所以初始化为0x01,移动1来使得亮的灯移动
定义一个direction 作为方向的判断符号,当direction为0的时候P1左移一位,相反为1的时候P1右移一位。
仿真
在keil中编译学好的代码,则会在本地该工程文件夹下的Object目录下生成一个后缀为.hex的文件,编译结果中也可以看到文件路径。
在Proteus中双击芯片,点击如图所示的位置,选择上述的hex文件即可进行仿真。
2.来回点灯
代码如下(示例):
#include <REGX52.H>void delay(void){unsigned int i = 30000; while(i--);}void main(void){unsigned char dat = 0x01, i=0, lastDat = 0x80, lastLight = 0xff, lastState = 0x01;int direction = 0;P1 = dat;delay();while(1){if (lastDat == 0x01){lastDat = 0x80;lastLight = 0xff;lastState = 0x01;P1 = lastState | (~lastLight);delay();}if (direction == 0){lastState <<= 1;//P1 <<= 1;P1 = lastState | (~lastLight);delay();if (P1 == (lastDat|(~lastLight))){lastLight >>= 1;lastDat >>= 1;direction = 1;} }if (direction == 1){lastState >>= 1;//P1 >>= 1;P1 = lastState|(~lastLight);delay();if (P1 == (0x01|(~lastLight))){direction = 0;}}//P1 = dat;}}
不仅定义了方向符号,还多定义了一个变量(0xff)右移与P1状态进行或运算来确保尾灯点亮。
3.按键操作
#include <REGX52.H>void button_led(){P1 = ~P1;#取反}void main(){P1 = 0xff;while(1){while(P3_2);//监测按下while(!P3_2);//弹起,完成一次按键操作button_led();//执行}}
实现功能:当按下一次按键就会使得P1取反,对应的管脚电平改变。
4.中断操作
#include <REGX52.H>void button_led(void) interrupt 0{P1 = ~P1;}void main(){EA = 1;EX0 = 1;IT0 = 1;while(1);}
实现功能:同3一样,通过按键来控制P1系列管脚的电平变化。
INT0对应的编号为0,INT1对应的编号为2,该编号为interrupt后的数字。
5.数码管
这里使用的是共阴极数码管,可以看见数码管段选接的地。
7个位选接在P0的7个位上。
根据数码管的灯接的位置,输入对应的码值就可以构造出对应图形的数字。
#include <REGX52.H>void delay(){unsigned int i=40000;while(i--);}void main(){unsigned char code tab[]={0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x76};#0-9码表unsigned int i=0;while(1){if (i>10){i=0;}P0 = tab[i];delay();i++;}}
数码管从0-9循环显示。
6 动态数码管
位选:左边的八个引脚对应的就是八个位选,跟单个数码管的位选功能一样。
段选:左边的1234为段选,段选表示指定指定哪些数码管亮,这里总共有四个数码管,所以有四个段选位,从左到右对应1234,哪个位输入高电平则对应的数码管可以亮。
例子:在数码管上显示4567
原理:循环改变位选,依次从1-4输出高电平,在对应数码管高电平时给位选输入对应的码值显示指定数字,通过这样一直刷新来达到一直显示数字的目的。
代码(该数码管为共阳数码管):
#include <REGX52.H>void main(){unsigned char duanxuan[] = {0x01, 0x02, 0x04, 0x08};unsigned int num=0, displayNum[] = {4, 5, 6, 7};unsigned char code tab[]={0xc0,//00xf9,//10xa4,//20xb0,//30x99,//40x92,//50x82,//60xf8,//70x80,//80x90,//90x88,//A0x83,//B0xc6,//C0xa1,//D0x86,//E0x8e, //F0x8c, //P0xc1,//U0x91,//Y0x7c,//L~0x40, //"-"0x00,//全亮0xff //熄灭};while(1){if(num == 4){num = 0;}P2 = 0x00;//消隐P0 = tab[displayNum[num]];P2 = duanxuan[num];num++;}}
效果
三、 练习题
使动态数码管显示:“-56-”,通过中断控制按键,按一次56减一个数,当减到45时再按一次回到56。
#include <REGX52.H>unsigned char disNum[] = {20, 5, 6, 20};void display(){unsigned char duanxuan[] = {0x01, 0x02, 0x04, 0x08};unsigned char code tab[]={0xc0,//00xf9,//10xa4,//20xb0,//30x99,//40x92,//50x82,//60xf8,//70x80,//80x90,//90x88,//A0x83,//B0xc6,//C0xa1,//D0x86,//E0x8e, //F0x8c, //P0xc1,//U0x91,//Y0x7c,//L~0x40, //"-"0x00,//全亮0xff //熄灭};int flag = 4;while(flag){flag--;P2 = 0x00;P0 = tab[disNum[flag]];P2 = duanxuan[flag];}}void key() interrupt 2{if (disNum[2] == 5 && disNum[1] == 4){disNum[2] = 6;disNum[1] = 5;}else if (disNum[2] == 0){disNum[2] = 9;disNum[1] = 4; }else{disNum[2] -= 1;}} void main(){EA = 1;EX1 = 1;IT1 = 1;while(1){display();}}
仿真1
总结
本文章为博主入门单片机的学习记录,希望可以帮助大家一起学习入门51单片机。