新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > 51单片机学习总结实例

51单片机学习总结实例

作者: 时间:2016-11-19 来源:网络 收藏
马上大四了,即将找工作。所以便把我学过的东西总结一下,系统一下。

接下来,就把我总结的结果跟大家分享下。

本文引用地址:https://www.eepw.com.cn/article/201611/318259.htm

这一章是51单片机,主要是程序实例。代码参考郭天祥的单片机教材。

是总括性的,适合于有一定单片机基础的同学,也可以给初学者做一个系统的学习主线。

这个博客里的涉及的源代码大家可以在这里下载http://download.csdn.net/detail/zhaole20094463/4427745

1.流水灯

/流水灯/
#include
#include//包含_crol_函数所在的头文件
#define uint unsigned int //宏定义 定义uint 在大项目中更加的方便
#define uchar unsigned char
void delayms(uint);
uchar aa;
void main()
{
aa=0xfe;
while(1)
{
P1=aa;
delayms(500);
aa=_crol_(aa,1);//aa左移一位
}
}
void delayms(uint xms)//延时时间约为1ms通过程序单步执行,看运行时间可得到
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}

通过调用系统函数的方式使流水灯实现循环左移。

2.数码管显示程序

/*锁存器用的是74HC573高电平通,低电平锁存*/
/*作用:高阻态 ,数据锁存 ,数据缓冲 (加强驱动能力)*/
/*循环显示1-A的数据*/
#include
#define uint unsigned int
#define uchar unsigned char
sbit dula=P2^6;
sbit wela=P2^7;
uchar num;
uchar code table[]={数码管段码表};
void main()
{
wela=1;//打开锁存器
P0=0xc0;//送入锁存信号
wela=0;//关闭锁存器
while(1)
{
for(num=0;num<16;num++)
dula=1;
P0=table[num];
delayms(500);
}
}
void delayms(uint xms)
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}

3.独立键盘检测

/*通过按键控制led亮灭*/
#include
#define uint unsigned int
#define uchar unsigned char
sbit key1=P3^4;
sbit led=P1^0;
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void main()
{
P3=0xff;//在对51单片机进行按键检测时,先要将引脚置1;
while(1)
{
if(key1==0)
{
delay(5);
if(key1==0)//按键消抖
{
led=0;
num++;
if(num==2)
num=0;
led=1;
}
}

4.矩阵键盘检测

/*检测矩阵键盘数码管显示0-F/
矩阵键盘的四列与P3.4~P3.7相连
4行与P3.0~P3.3
#include
#define uchar unsinged char
#define uint unsigned int
sbit dula=P2^6;
sbint wela=P2^7;
uchar code table[]={段码表};
void delayms(uint xms);
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
void display(uchar num)显示函数
{
P0=table[num];
dula=1;
dula=0;
}
void matrixkeyscan()//矩阵键盘的检测
{
uchar temp,key;
P3=0xfe;//打开P3.7,P3.7置0.检测高四位
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)//是否有键被按下
{
delayms(10);
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)//按键消抖
{
temp=P3;
switch(temp)
{
case 0xee:key=0;break;
case 0xde:key=1;break;
case 0xbe:key=2;break
case 0x7e:key=3:break;
}
while(temp!=0xf0)//检测按键是否弹起,如果没有弹起循环停在这里。
{
temp=P3;
temp=temp&0xf0;
}
display(key);
}
}
。。。。。。。。。。。。。。。。。。。
如下程序依次增加
令P3=0xfd,打开P3.6,P3.6置低,检测高四位 依次为 4,5,6,7
然后令P3= 0xfb 0xf7
}
void main()
{
P0=0;//关闭所有数码管的段选
dula=1;
dula=0;
P0=0xc0;
wela=1;
wela=0;
while(1)
{
matrixkeyscan();//不停调用键盘扫描程序
此程序关键在于这个函数,矩阵键盘的扫描算法
}
}

5.1602液晶屏显示子函数

//
这个程序主要是有这样几个子函数,关于lcd写命令和写数据的
#include
#define uchar unsigned char
#define uint unsigned int
uchar code table[]="zhaole20094463";
uchar code table1[]="love Embedded systems";
sbit lcden=P3^4;//lcd使能端
sbit lcdrs=P3^5;//lcd数据命令选择端
uchar num;
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void write_com(uchar com)//lcd写命令函数
{
lcdrs=0;
P0=com;
delay(5);
lcden=1;
delay(5);
lceen=0;
}


void write_data(uchar date)//lcd写数据
{
lcdrs=1;
P0=date;
delay(5);
lcden=1;
delay(5);
lcden=0;
}


void init()
{
lcden=0;
write_com(0x38);//设置16*2显示,5*7点阵,8位数据接口
write_com(0x0c);//设置开显示,不显示光标
write_com(0x06);//写第一个字符后地址指针加1
write_com(0x01);//显示清0,数据指针清0
}
void main()
{
init();
write_com(0x80);//数据指针定位在第一行的第一个字处
for(num=0;num<14;num++)
{
write_data(table[num]);
delay(5);
}
write_com(0x80+0x40);//数据指针定位在第二行的第一个字处
for(num=0;num<21;num++)
{
write_data(table1[num]);
delay(5);
}
while(1);
}

5.2 12864显示子函数

#include
#include
#include


#define uchar unsigned char
#define uint unsigned int


#define LCD_data P0;//数据口


sbit LCD_RS=P3^5; //数据选择输入
sbit LCD_RW=P3^6; //液晶读写控制
sbit LCD_EN=P3^4; //液晶使能控制端
sbit LCD_PSB=P3^7; //串并方式控制


void delay_1ms(uint )
{
uint i,j;
for(j=0j for(i=0;i<110;i++);
}
/*PS=L,RW=L,E=高脉冲,D0~D7=指令码*/
void write_cmd(uchar cmd)
{
LCD_RS=0;
LCD_RW=0;
LCD_EN=0;
P0=cmd;
delay_1ms(5);
LCD_EN=0;
}
/*写显示数据到LCD*/
/*RS=H,RW=L,E=高脉冲,D0~D7=数据
void write_dat(uchar dat)
{
LCD_RS=1;
LCD_RW=0;
LCD_EN=0;
P0=dat;
delay_1ms(5);
LCD_EN=1;
dealy_1ms(5);
LCD_EN=0;
}
/*设定显示位置*/
void LCD_pos(uchar X,uchar Y)
{
uchar pos;
if(X==0)
{X=0x80;}
else if(X==1);
{X=0x90;}
else if(x==2)
{X=0x88;}
else if(X==3)
{X=0x98;}
pos=X+Y;
write_cmd(pos);//显示地址
}


/*LCD初始化设置*/
void lcd_init()
{
LCD_PSB=1; //并口方式
write_cmd(0x30);//基本指令操作
delay_1ms(5);
write_cmd(0x0C);//先是开,关光标
delay_1ms(5);
write_cmd(0x01);//清除LCD的显示内容
delay_1ms(5);
}

6.定时器中断

/*用定时器0的方式1实现第一个发光管以1s亮灭*/
定时器/计数器4种工作方式
1,方式0 13位计数器 高8位和低5位
2,方式1 16位计数器
3,方式2 自动恢复初值 8位
4,方式3 只适用于T0,不适用于T1 8位

45872初值的计算
晶振:11.0592M
机器周期:计数一次的时间=12*(1/11.0592M)51单片机是12个时钟周期为一个机器周期
=1.09US 指令周期由整数个机器周期组成
45872 =50Ms/1.09us


//
#include
#define uchar unsigned char
#define uint unsigned int
sbit led1=P1^0;
uchar num;
void main()
{
TMOD=0x01;//设置定时器0工作方式1
TH0=(65535-45872)/256;//装初值11.0592M晶振定时50ms为45872
TL0=(65535-45872)%256;
EA=1; //开总中断
ET0=1; //开定时器0中断
TR0=1; //启动定时器0
while(1) //程序停在这里等待中断的发生
}


void T0_time() interrupt 1
{
TH0=(65535-45872)/256;
TL0=(65535-45872)%256;
num++;
if(num==20)
{
num=0;
led1=~led1;
}
}

7.串口通信

//
上位机通过串口调试助手发送一个字符x,单片机收到字符后返回给上位机“I get x”
串口波特率设置为9600bps。
#include
#define uchar unsigned char
#define uint unsigned int
uchar flag,a,i;
uchar code table[]="I get";
void init()
{
TMOD=0x20;//设置T1定时器工作方式为2 8位初值自动重装的8位定时器
TH1=0xfd;//T1定时器装初值(高八位) 控制串口通信的波特率(由定时器1的溢出率控制)
TL1=0xfd;///T1定时器装入初值(低八位)
TR1=1; //定时器1运行控制位 置一启动定时器
REN=1; //允许串口接收
SM0=0;
SM1=1; //设置串口工作方式为一
EA=1; //全局中断允许位 置一开全局中断
ES=1; //串口中断允许位
}


void main()
{
init();
` while(1)
{
if(flag==1)
{
ES=0;
for(i=0;i<6;i++)
{
SBUF=table[i];
while(!TI)
TI=0;//发送中断标志 发送数据完成后触发中断 硬件置一 必须软件清零
}
SBUF=a;// 串口发送数据
while(!TI);
TI=0;
ES=1;
flag=0;
}

}


void ser() interrupt 4 //串口中断服务程序
{
RI=0; // 收到数据硬件置一,由软件清零
a=SBUF; //将寄存器的值 赋给a
flag=1; //标志位
}
注意:51单片机的特殊之处在于,SBUF既是串口接收寄存器也是串口发送寄存器,取决于
SBUF所在赋值符号“=”左右的位置


此程序中共用的串口中断,


定时器1中断 特殊功能寄存器SBUF


中断响应的条件


中断源有中断请求 此中断源允许位为1 cpu开中断(即EA=1)以上三个条件同时满足


串口通信设置


确定串口通信波特率(编程TMOD寄存器定时器工作方式寄存器)

计算定时器初值转载THX TLX

确定串行口工作方式(编程SCON寄存器串行口控制方式寄存器)

串行口工作在中断方式时,要进行中断设置如TI,RI软件清零

8.I2C总线通信模拟子函数

/*/
因为51单片机没有I2C总线,所以采用模拟I2C通信
1,总线初始化
void init()
{
SCL=1;
delay();
SDA=1;
delay();
}
2,启动信号
void start()
{
SDA=1;
delay(1);
SCL=1;
delay();
SDA=0;
delay();
}
3,应答信号
void respons()
{
uchar i=0;
SCL=1;
delay();
while((SDA==1)&&(i<255))
i++;
SCL=0;
delay();
}
4,停止信号
void stop()
{
SDA=0;
delay();
SCL=1;
delay();
SDA=1;
delay();
}
5,写一个字节
void writebyte(uchar date)
{
uchar i,temp;
temp=date;
for(i=0;i<8;i++)
{
temp=temp<<1;
SCL=0;
delay();
SDA=CY;
delay();
SCL=1;
delay();
}
SCL=0;
delay();
SDA=1;
delay();
}
6,读一个字节
uchar readbyte()
{
uchar i,k;
SCL=0;
delay();
SDA=1;
for(i=0;i<8;i++)
{
SCL=1;
delay();
k=(k<<1)|SDA;
SCL=0;
delay();
}
delay();
return k;
}

9.看门狗

//
关于51单片机中的看门狗寄存器
D5 EN_WDT 看门狗允许位
D4 CLK_WDT 看门狗清零
D3 IDLE_WDT 看门狗IDLE模式位
PS0 PS1 PS2 看门狗定时器预分频值
这三个寄存器置不同的值决定不同的看门狗溢出时间
看门狗溢出时间=(N*预分频数*32768)/晶振频率
#include
#define uchar unsigned char
#define uint unsigned int
sfr WDT_CONTR=0xe1;//定义看门狗寄存器 reg52.h中没有对它进行定义
sbit led1=P1^0;
void delayms(uint xms)
{
uint i,j;
for(i=xms;j>0;j--)
for(j=110;j>0;j--);
}

void main()
{
WDT_CONTR=0x35;//0x35=0011 0101设置预分频数为 64 溢出时间为2.0971s
led1=0;
delayms(500);
led1=1;
while(1)
{
delayms(1000);
WDT_CONTR=0x35;//喂狗语句将D4不断置1,一旦D4被清零则看门狗复位
}
}

10.软件实现系统复位

STC ISP/IAP控制寄存器(ISP_CONTR)
D7 ISPEN 功能允许位 0禁止编程改变flash 1允许
D6 SWBS 0软件选择从用户应用程序区启动 1从ISP程序区启动
D5 SWRST 不操作 1产生系统软件复位,硬件自动清零
D2 WT2
D1 WT1
D0 WT0 编程设定CPU等待的最长时间,对flash进行读操作,写操作,擦除操作必须在这个时间内
SWBS=0 SWRST=1(软复位) 从用户应用程序区(AP区)软件复位并切换到用户应用程序区开始执行程序
从哪里复位取决于程序在哪里执行
SWBS=1 SWRST=1 从ISP监控程序区软件复位并切换ISP监控程序区开始执行程序
使用方法:
进行软件复位时
首先
sfr ISP_CONTR=0xe7;定义ISP/IAP控制寄存器
然后再需要软件复位的地方加入如下语句即可
ISP_CONTR=0x20//用软件复位到用户应用程序区(AP),重新开始执行程序

11.DS18B20编程应用子函数

//
Ds18B20的编程子函数
DS18B20是单总线接口的温度传感器,应用范围很广泛

#include
#include
#define uchar unsigned char
#define uint unsigned int
sbit ds=P2^2;//温度传感器信号线
uint temp;//定义整型的温度数据
float temp;//定义浮点型的温度数据
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}




void dsreset(void)//DS18B20复位,初始化函数
{
uint i;
ds=0;
i=103;
while(i>0)i--;
ds=1;
i=4;
while(i>0)i--;
}


bit tempreadbit(void)//读1位数据函数
{
uint i;
bit dat;
ds=0;i++;//i++起延时作用
ds=1;i++;i++;
dat=ds;
i=8;while(i>0)i--;
return(dat);
}


uchar tempread(void)//读1个字节数据函数
{
uchar i,j,dat;
dat=0;
for(i=1;i<=8;i++)
{
j=tempreadbit();
dat=(j<<7)|(dat>>1);//读出的数据最低位在最前面,这样刚好一个字节在dat里
}
return(dat);
}
void tempwritebyte(uchar dat)//向DS18B20写一个字节数据函数
{
uint i;
uchar j;
bit testb;
for(j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if(testb)//写1
{
ds=0;
i++;i++;
ds=1;
i=8;while(i>0)i--;
}
else//写0
{
ds=0;
i=8;while(i>0)i--;
ds=1;
i++;i++;
}
}
}


void tempchange(void)//DS18B20 开始获取温度并转换
{
dsreset();
delay(1);
tempwritebyte(0xcc);//写 跳过读ROM指令
tempwritebyte(0x44);//写 温度转换指令
}


uint get_temp()
{
uchar a,b;
dsreset();
delay(1);
tempwritebyte(0xcc);
tempwritebyte(0xbe);//读内部ram中的9字节
a=tempread();//读低8位
b=tempreda();//读高8位
temp=b;
temp<<=8;
temp=temp | a;//两个字节组合为1个字
f_temp = temp*0.0625;//温度在寄存器中为12位,分辨率为0.0625 厂家出厂时默认精度为12位,所以乘以0.0625
temp=f_temp*10+0.5; //乘以10表示小数点后面只取一位,加0.5是为了四舍五入
f_temp=f_temp+0.05;
return temp;
}

12.内部ram的扩展

51单片机存储器模式一共有三种
small模式 默认变量存储在单片机内部的128B RAM中
无声明均以这个模式存储
compact模式 默认变量存储在单片机内部的 256B RAM中
关键字 pdata :unsinged char pdata a[100]
large 模式 默认变量均存储在64K的RAM区包括内部ram和外部ram
关键字 xdata:unsingned char xdata a[100]
三种模式的不同:访问速度由快到慢

这个博客里的涉及的源代码大家可以在这里下载http://download.csdn.net/detail/zhaole20094463/4427745



关键词: 51单片机学习总

评论


技术专区

关闭