本文用来记录博主学习单片机的过程与方法,希望对入门的同学有所帮助
该篇博客主要讲授如何基于proteus(仿真)+keil实现51单片机的点灯操作,本篇为入门篇,所以会介绍如何使用Proteus进行仿真,以及代码编写思路,实现简单的功能效果。
该软件的安装教程就不多赘述,网上资源很多,主要讲解满足51学习的使用,几个常用的功能。
在Proteus搭成这样即可完成本文章下除了5.数码管的其他所有的仿真任务。
1、常见原件库,按p键即可进行搜索,搜索指定元器件代号既可选入。
51单片机:AT89C52
排阻:RP1(主要用于P0口做串口使用的时候需要接上拉电阻)
LED:LED
按键:BUTTON
数码管:display
动态数码管:7SEG
2、电源、地等元件库。
代码如下(示例):
#include
void delay(void)
{
unsigned int i = 40000;
while(i--);
}
void main(void)
{
unsigned char dat = 0x01, i=0;
unsigned int direction = 0;
//LED共阴,高电平点亮,设置0x01
P1 = 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文件即可进行仿真。
代码如下(示例):
#include
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状态进行或运算来确保尾灯点亮。
#include
void button_led(){
P1 = ~P1;#取反
}
void main(){
P1 = 0xff;
while(1){
while(P3_2);//监测按下
while(!P3_2);//弹起,完成一次按键操作
button_led();//执行
}
}
实现功能:当按下一次按键就会使得P1取反,对应的管脚电平改变。
#include
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后的数字。
这里使用的是共阴极数码管,可以看见数码管段选接的地。
7个位选接在P0的7个位上。
根据数码管的灯接的位置,输入对应的码值就可以构造出对应图形的数字。
#include
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循环显示。
位选:左边的八个引脚对应的就是八个位选,跟单个数码管的位选功能一样。
段选:左边的1234为段选,段选表示指定指定哪些数码管亮,这里总共有四个数码管,所以有四个段选位,从左到右对应1234,哪个位输入高电平则对应的数码管可以亮。
例子:在数码管上显示4567
原理:循环改变位选,依次从1-4输出高电平,在对应数码管高电平时给位选输入对应的码值显示指定数字,通过这样一直刷新来达到一直显示数字的目的。
代码(该数码管为共阳数码管):
#include
void main(){
unsigned char duanxuan[] = {0x01, 0x02, 0x04, 0x08};
unsigned int num=0, displayNum[] = {4, 5, 6, 7};
unsigned char code tab[]={
0xc0,//0
0xf9,//1
0xa4,//2
0xb0,//3
0x99,//4
0x92,//5
0x82,//6
0xf8,//7
0x80,//8
0x90,//9
0x88,//A
0x83,//B
0xc6,//C
0xa1,//D
0x86,//E
0x8e, //F
0x8c, //P
0xc1,//U
0x91,//Y
0x7c,//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
unsigned char disNum[] = {20, 5, 6, 20};
void display(){
unsigned char duanxuan[] = {0x01, 0x02, 0x04, 0x08};
unsigned char code tab[]={
0xc0,//0
0xf9,//1
0xa4,//2
0xb0,//3
0x99,//4
0x92,//5
0x82,//6
0xf8,//7
0x80,//8
0x90,//9
0x88,//A
0x83,//B
0xc6,//C
0xa1,//D
0x86,//E
0x8e, //F
0x8c, //P
0xc1,//U
0x91,//Y
0x7c,//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