蓝桥杯单片机编程笔记Word文件下载.docx
《蓝桥杯单片机编程笔记Word文件下载.docx》由会员分享,可在线阅读,更多相关《蓝桥杯单片机编程笔记Word文件下载.docx(41页珍藏版)》请在冰豆网上搜索。
ﻩP2=((P2&
0x1f)|0xc0);
P0=(1<<dspcom);
P2=P2&
0x1f;
//段码输入
P2=((P2&0x1f)|0xe0);
ﻩP0=tab[dspbuf[dspcom]];
ﻩif(++dspcom==8)
ﻩdspcom=0;
}
注意:
这里1左移dspcom位,刚开始dspcom=0,则1左移dspcom位依旧为1,接着dspcom每次自增1,1对应二进制00000001,即把1每次向左移,每次都比上一次多移一位,直至8位移完,对应8个数码管。
定时器配置:
这里只需记住定时器的配置,知道怎么使用就可以了。
首先有两个定时器,T0和T1,(也有的单片机有T2),定时器有4种工作方式0,1,2,3;
其中最常用的是方式1(16位),其次是方式2(8位自动重装,串口通讯中断会用到)。
定时器需要配置:
TMOD|=0x01;
配置成使用定时器0,工作方式为1;
同理使用定时器1工作方式1:
TMOD |=0x10;
则同时使用两个定时器且工作方式为1,那么可以:
TMOD|=0x11;
定时器1配置成工作方式2:
TMOD|=0x20;
接着配置(以定时器0举例):
TH0=(65535-2000)/256;
//配置初值
TL0=(65535-2000)%256;
ET0=1;
TR0=1;
//定时0中断
EA=1;
//总中断
定时器1也是同理的,只不过0要改成1.
接着定时中断函数和优先级:
定时器0
voidisr_timer_0(void) interrupt1//默认中断优先级1
TH0=(65536-2000)/256;
TL0 =(65536-2000)%256;
//定时器重载
display();
定时器1:
voidisr_timer_1(void) interrupt 3 //默认中断优先级3
TH0=(65536-2000)/256;
TL0 =(65536-2000)%256;
//定时器重载
display();
定时器0优先级为1,定时器1为3,串口中断优先级为4,总共有5个中断源,后面还会介绍外部中断和串口中断。
数码管动态扫描,显示函数放在定时中断函数里面,2ms扫一次是最稳定的!
!
三、矩阵键盘
矩阵键盘需要死记了!
这里不再讲独立键盘。
第二种单片机键盘扫描代码(没有消抖):
sfrP4^4=0xC0;
//键盘定义
sbit r1=P3^0;
//4行
sbitr2=P3^1;
sbitr3=P3^2;
sbit r4=P3^3;
//4列
sbitc1=P4^4;
sbitc2=P4^2;
sbitc3=P3^5;
sbitc4=P3^4;
//读取矩阵键盘键值
unsignedcharkey_scan()
{
unsignedcharkey_value;
r1=0;
r2=r3=r4=1;
ﻩc1=c2=c3=c4=1;
if(!
c1)key_value=0;
elseif(!
c2)key_value=1;
elseif(!
c3)key_value=2;
c4)key_value=3;
r2=0;
ﻩr1=r3=r4=1;
ﻩc1=c2=c3=c4=1;
ﻩif(!
c1)key_value=4;
else if(!
c2)key_value=5;
ﻩelseif(!
c3)key_value=6;
else if(!
c4) key_value=7;
r3=0;
r2=r1=r4=1;
ﻩc1=c2=c3=c4=1;
ﻩif(!
c1)key_value=8;
ﻩelseif(!
c2) key_value=9;
elseif(!
c3)key_value=10;
ﻩelseif(!
c4)key_value=11;
r4=0;
r2=r3=r1=1;
ﻩc1=c2=c3=c4=1;
if(!
c1)key_value=12;
ﻩelse if(!
c2)key_value=13;
elseif(!
c3)key_value=14;
else if(!
c4)key_value=15;
ﻩreturnkey_value;
四、串口通讯和串口中断
串口中断配置只需记住几个寄存器就行了,
初始化:
SCON =0x50;
//串口配置成模式1
TMOD|=0x20;
//定时器1,方式2,8位自动重装
TH1=256-(unsigbedchar)(SYSTEMCLOK/BAUDRATE/384+0.5);
//定时初值
ﻩES=1;
ﻩ //串口中断打开
ﻩTR1=1;
//启动定时器1
ﻩEA=1;
ﻩ//总中断打开
这里必须使用定时器1,不能用定时器0.
下面是模块化的函数:
void Uart_Init()
SCON= 0x50;
TMOD |=0x20;
ﻩTH1=256-(SYSREMCLOCK/BAUDRATE/384+0.5);
ﻩES=1;
TR1=1;
EA=1;
}
void UartSend(unsignedchar*pBuff,intlength)
unsignedcharc;
int i=0;
for(i=0;
i<
length;
i++)
ﻩc=pBuff[i];
SBUF=c;
while(TI==0);
TI=0;
接收数据可以这样写:
定义全局变量:
unsignedcharuart_buf[100];
//串口缓冲区
unsignedintuart_Count=0;
//串口数据长度
voiduart_inte()interrupt 4
ﻩunsignedcharc;
if(RI)
{
ﻩﻩRI=0;
ﻩﻩc=SBUF;
ﻩuart_buf[uart_Count]=c;
ﻩﻩuart_Count++;
}ﻩﻩ
如果可以指定的接收,可以这样写
//串口中断服务函数
void isr_uart(void)interrupt4{
if(RI){
RI=0;
//清除接收标志位
rxbuf[rxcnt] =SBUF;
if(rxbuf[rxcnt] =='
\n'
){
rxcnt=0;
rx_over=1;
ES =0;
//回车为接收结束标志,检测到回车符后,关闭串口中断
}
ﻩﻩelse{
ﻩrxcnt++;
ﻩﻩ}
}
当接收完一帧数据时关闭串口中断,设一个标志位,处理完之后再打开。
#include"
reg51.h"
#include"
intrins.h"
typedefunsigned char BYTE;
typedef unsignedint WORD;
BYTEcode_tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};
chararry[10]="
I CAN PLAY";
unsignedchar x;
#define FOSC11059200//12000000L //系统频率
#defineBAUD115200 //串口波特率
#defineNONE_PARITY 0 //无校验
#defineODD_PARITY 1 //奇校验
#defineEVEN_PARITY2 //偶校验
#defineMARK_PARITY 3 //标记校验
#defineSPACE_PARITY 4 //空白校验
#define PARITYBITNONE_PARITY //定义校验位
sfr AUXR=0x8e;
//辅助寄存器
sfr P_SW1=0xA2;
//外设功能切换寄存器1
#defineS1_S0 0x40 //P_SW1.6
#defineS1_S10x80 //P_SW1.7
sbitP22=P2^2;
bitbusy;
voidSendData(BYTEdat);
voidSendString(char*s);
voidmain()
ACC= P_SW1;
ACC&
=~(S1_S0| S1_S1);
//S1_S0=0S1_S1=0
P_SW1 =ACC;
//(P3.0/RxD,P3.1/TxD)
//ACC= P_SW1;
// ACC&
=~(S1_S0|S1_S1);
//S1_S0=1S1_S1=0
//ACC |=S1_S0;
//(P3.6/RxD_2,P3.7/TxD_2)
//P_SW1 =ACC;
//
//ACC=P_SW1;
// ACC &
=~(S1_S0|S1_S1);
//S1_S0=0S1_S1=1
// ACC|=S1_S1;
//(P1.6/RxD_3,P1.7/TxD_3)
// P_SW1 =ACC;
//#if (PARITYBIT==NONE_PARITY)
SCON=0x50;
//8位可变波特率
//#elif(PARITYBIT==ODD_PARITY)|| (PARITYBIT ==EVEN_PARITY)|| (PARITYBIT==MARK_PARITY)
// SCON =0xda;
//9位可变波特率,校验位初始为1
//#elif(PARITYBIT==SPACE_PARITY)
// SCON= 0xd2;
//9位可变波特率,校验位初始为0
//#endif
AUXR= 0x40;
//定时器1为1T模式
TMOD = 0x20;
//定时器1为模式2(8位自动重载)
TL1 = (256-(FOSC/32/BAUD));
//设置波特率重装值
TH1 =(256-(FOSC/32/BAUD));
TR1=1;
//定时器1开始工作
ES= 1;
//使能串口中断
EA=1;
while
(1)
ﻩ{
//SendString(arry);
SendString("
ICAN PLAY~~\r\n");
//上位机显示接收文本模式
//ﻩSendData(x);
}
/*----------------------------
UART中断服务程序
-----------------------------*/
voidUart() interrupt4using1
if(RI)//单片机接收数据,发送数字0~9,可在数码管上显示,发送hex模式
{
RI=0;
//清除RI位
// P0= SBUF;
ﻩx=SBUF;
//将缓存器的数据赋值给x
P0=0xff;
//消隐
ﻩﻩP2|=0xe0;
ﻩP2&=0x1f;
ﻩﻩ
P0=code_tab[x];
ﻩ//段选
ﻩP2|=0xe0;
ﻩP2&=0x1f;
ﻩP0=0x01;
ﻩﻩ//位选第一位
ﻩﻩP2|=0xc0;
ﻩﻩP2&=0x3f;
}
if (TI)
{
TI=0;
//清除TI位
busy =0;
//清忙标志
/*----------------------------
发送串口数据
----------------------------*/
void SendData(BYTE dat)
while(busy);
//等待前面的数据发送完成
ACC=dat;
//获取校验位P(PSW.0)
if(P) //根据P来设置校验位
{
#if(PARITYBIT== ODD_PARITY)
TB8=0;
//设置校验位为0
#elif(PARITYBIT==EVEN_PARITY)
TB8= 1;
//设置校验位为1
#endif
}
else
{
#if(PARITYBIT==ODD_PARITY)
TB8 = 1;
//设置校验位为1
#elif (PARITYBIT ==EVEN_PARITY)
TB8=0;
//设置校验位为0
#endif
busy=1;
SBUF=ACC;
//写数据到UART数据寄存器
/*----------------------------
发送字符串
----------------------------*/
voidSendString(char*s)
while(*s) //检测字符串结束标志
{
SendData(*s++);
//发送当前字符
记不住可以看手册!
!
reg51.h"
#include "
typedefunsigned charBYTE;
typedefunsignedintWORD;
#defineFOSC11059200L
#define BAUD115200
sfr AUXR=0x8e;
//辅助寄存器
sbitP22=P2^2;
bit busy;
voidSendData(BYTE dat);
voidSendString(char*s);
voidmain()
ﻩSCON=0x50;
ﻩAUXR=0x40;
ﻩ//设置定时器T1为1T,即一个机器周期模式
TMOD=0x20;
ﻩTL1=(256-(FOSC/32/BAUD));
TH1=(256-(FOSC/32/BAUD));
ﻩES=1;
EA=1;
SendString("
Hello"
);
ﻩwhile
(1);
voidUart()interrupt 4 using1
if(RI)
ﻩRI=0;
ﻩﻩP0=SBUF;
ﻩ}
if(TI)
TI=0;
ﻩbusy=0;
voidSendData(BYTEdat)
while(busy);
busy=1;
SBUF=dat;
voidSendString(char*s)
ﻩwhile(*s)
{
SendData(*s++);
五、外部中断的使用
#include<
reg52.h>
sbitL1=P0^0;
intmain(){
IT0=1;
//IT0=1,下降沿触发外部中断0,IT0=0边沿触发
ﻩEX0=1;
//使用外部中断0
ﻩEA=1;
while
(1){
ﻩ}
void Ex_int0()interrupt0//外部中断优先级最高
P2=((P2&0x1f)|0x80);
ﻩL1=~L1;
P2=(P2&
0x1f);
}
其中,外部中断的引脚控制是P3^2,P3^3,即对应独立按键的S5,S4。
六、实时时钟DS1302的使用
蓝桥杯提供函数,解释为:
里面的命令和写入的数据可以看芯片手册:
左侧的READ、WRITE分别是读写的命令,BIT7-BIT0是要写入的数据,根据需要进行配置。
DS1302只需记住这两个函数即可:
Write_Ds1302(,)与Read_Ds1302(x),配置看手册。
重点:
芯片表说明:
第一行:
秒->
因为秒的范围是0-59,所以6,5,4位表示秒的十位,3,2,1,0表示个位,十位最大是5,所以三位即可。
第二行:
跟上面一样;
第三行:
7位:
1为12小时制,0为24小时制;
5位:
12小时制时为0表示上午,1表示下午,24小时制时,和4位一起表示小时的十位;
其余的时间一样的表示。
倒数第二行:
只看7位:
为1时禁止写数据,所以开始写数据时必须置0;
读数时:
需要加“写操作这一行代码”。
读的话直接按照命令读即可。
DS1302进阶(BCD码转换):
解决之前60秒不能进位的问题。
1)写入初始值时,要把10十进制数转换为BCD码,
例:
写入时间->
17:
58:
50
Ds1302_Single_Byte_Write(0x8e,0x00);
//写操作
ﻩDs1302_Single_Byte_Write(0x85, ((17/10)<<
4| (17%10)));
//写时
Ds1302_Single_Byte_Write(0x83,((58/10)<
<4|(58%10)));
//写分
Ds1302_Single_Byte_Write(0x81, ((50/10)<
<
4|(50%10)));
//写秒
Ds1302_Single_Byte_Write(0x8e,0x80);
//写保护
即转换的公式是:
((Value/10)<<
4|(Value%10)),可以写一个settime()函数。
2) 读数:
读回来的数要进行转换成十进制数
((ReadValue&0x70)>>
4)*10+(ReadValue&
0x0F);
八进制转十进制->
ReadValue=Ds1302_Single_Byte_Read(0x85);
ﻩﻩhour=((ReadValue&
0x70)>
>
4)*10 +(ReadValue&
!
(这句一定不要省)ﻩDs1302_Single_Byte_Write(0x00, 0x00);
//写操作
ﻩReadValue=Ds1302_Single_Byte_Read(0x83);
ﻩﻩminute=((ReadValue&0x70)>>
4)*10+(ReadValue&
0x0F);
Ds1302_Single_Byte_Write(0x00,0x00);
ReadValue=Ds1302_Single_Byte_Read(0x81);
ﻩsec=((ReadValue&
0x70)>>4)*10 +(ReadValue&
ﻩDs1302_Single_Byte_Write(0x00,0x00);
显示:
ﻩdspbuf[0]=hour/10;
ﻩdspbuf[1]=hour%10;
dspbuf[2]=minute/10;
ﻩdspbuf[3]=minute%10;
ﻩdspbuf[4]=sec/10;
ﻩﻩdspbuf[5]=sec%10;
七、PCF8591与IIC总线的使用
(1)IIC总线的使用:
比赛提供了IIC的两个库文件,IIC.h;
IIC.c,其中需要注意的函数是:
其中,该函数是初始化的,当使用AD转换的时候需要在main函数开始时调用,该函数内部只需看这句代码即可:
i2c_sendbyte(0x03);
//ADC通道3,板上有4个模拟输入口,分别为0,1,2,3;
设置哪一个模拟输入口就是根据这句代码,0x03表示通道3,这是根据芯片手册配置的,如图:
8位前6位不用管,都为0,最后两位就是配置选择哪一个通道的。
第二个函数:
读取AD转换后的数值,这个函数直接调用就可以了,函数内部如何实现不用管,但是需要注意的是:
该函数扫描调用最好是100ms。
第三个函数,上面的都是AD转换,即模拟信号转数字信号,下面这个函数是DA转换