蓝桥杯总结
基础篇
1、数码管显示
2、LED
3、蜂鸣器
4、继电器
5、独立按键
6、矩阵按键
7、定时器
8、PWM
9、串口
10、NE555定时器
11、DS18B20(温度传感器)
12、DS1302(RTC实时时钟)
13、AT24C02(EEPROM)
14、PCF8591(A/D转换)
15、超声波测距
提高篇
1、LCD12232
2、1602点阵
3、按键长按/短按
4、依次输入8个数,数码管依次显示,未输入位用“-”代替
基础模块
#include<STC15F2K60S2.H>
#define uchar unsigned char
uchar yi,er,san,si,wu,liu,qi,ba;
uchar table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff};
void Init_HC138(uchar n)
{
switch(n)
{
case 4:
P2 = (P2 & 0X1f) | 0x80; //LED
break;
case 5:
P2 = (P2 & 0X1f) | 0xa0; //蜂鸣器、继电器
break;
case 6:
P2 = (P2 & 0X1f) | 0xc0; //数码管位选
break;
case 7:
P2 = (P2 & 0X1f) | 0xe0; //数码管段选
break;
}
}
void All_Init() //初始化函数,关闭LED灯、蜂鸣器、继电器
{
Init_HC138(4);
P0 = 0xff;
Init_HC138(5);
P0 = 0x00;
}
void SMG_show(uchar dat,uchar pos) //单个数码管显示子函数
{
Init_HC138(6);
P0 = 0x01 << pos;
Init_HC138(7);
P0 = dat;
}
void display1(uchar yi,uchar er) //1、2数码管显示函数
{
SMG_show(table[yi], 0);
Delay1ms();
SMG_show(table[er], 1);
Delay1ms();
}
void display2(uchar san,uchar si) //3、4数码管显示函数
{
SMG_show(table[san], 2);
Delay1ms();
SMG_show(table[si], 3);
Delay1ms();
}
void display3(uchar wu,uchar liu) //5、6数码管显示函数
{
SMG_show(table[wu], 4);
Delay1ms();
SMG_show(table[liu], 5);
Delay1ms();
}
void display4(uchar qi,uchar ba) //7、8数码管显示函数
{
SMG_show(table[qi], 6);
Delay1ms();
SMG_show(table[ba], 7);
Delay1ms();
}
void Delay1ms() //@11.0592MHz 延迟函数
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
void main()
{
All_Init();
while(1)
{
display1(yi,er);
display2(san,si);
display3(wu,liu);
display4(qi,ba);
Init_HC138(6); //消隐
P0=0x00;
}
}
独立按键/矩阵按键
void keyscan(void) //独立按键函数 J5
{
if(P30==0) //P30->S7
{
Delayms(5);
if(P30==0)
{
//自定义
}
while(!P30);
}
else if(P31==0) //P31->S6
{
Delayms(5);
if(P31==0)
{
//自定义
}
while(!P31);
}
else if(P32==0) //P32->S5
{
Delayms(5);
if(P32==0)
{
//自定义
}
while(!P32);
}
else if(P33==0) //P33->S4
{
Delayms(5);
if(P33==0)
{
//自定义
}
while(!P33);
}
}
void Keyscan16(void) //矩阵按键函数 KBD
{
uchar temp;
P44=0;P42=1;P3=0X7F;
temp=P3;
temp=temp&0x0f;
if(temp!=0x0f)
{
Delayms(5);
temp=P3;
temp=temp&0x0f;
if(temp!=0x0f)
{
temp=P3;
switch(temp)
{
case 0x7e: num=0; break; //S7
case 0x7d: num=1; break; //S6
case 0x7b: num=2; break; //S5
case 0x77: num=3; break; //S4
}
while(temp!=0x0f)
{
temp=P3;
temp=temp&0x0f;
}
}
}
P44=1;P42=0;P3=0XBF;
temp=P3;
temp=temp&0x0f;
if(temp!=0x0f)
{
Delayms(5);
temp=P3;
temp=temp&0x0f;
if(temp!=0x0f)
{
temp=P3;
switch(temp)
{
case 0xbe: num=4; break; //S11
case 0xbd: num=5; break; //S10
case 0xbb: num=6; break; //S9
case 0xb7: num=7; break; //S8
}
while(temp!=0x0f)
{
temp=P3;
temp=temp&0x0f;
}
}
}
P44=1;P42=1;P3=0XDF;
temp=P3;
temp=temp&0x0f;
if(temp!=0x0f)
{
Delayms(5);
temp=P3;
temp=temp&0x0f;
if(temp!=0x0f)
{
temp=P3;
switch(temp)
{
case 0xde: num=8; break; //S15
case 0xdd: num=9; break; //S14
case 0xdb: num=10; break; //S13
case 0xd7: num=11; break; //S12
}
while(temp!=0x0f)
{
temp=P3;
temp=temp&0x0f;
}
}
}
P44=1;P42=1;P3=0XEF;
temp=P3;
temp=temp&0x0f;
if(temp!=0x0f)
{
Delayms(5);
temp=P3;
temp=temp&0x0f;
if(temp!=0x0f)
{
temp=P3;
switch(temp)
{
case 0xee: num=12; break; //S19
case 0xed: num=13; break; //S18
case 0xeb: num=14; break; //S17
case 0xe7: num=15; break; //S16
}
while(temp!=0x0f)
{
temp=P3;
temp=temp&0x0f;
}
}
}
}
定时器
void Timer0Init(void) //100微秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xAE; //设置定时初值
TH0 = 0xFB; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
void SericeTimer0() interrupt 1
{
//自定义
}
void main()
{
EA=1; //使能定时器T0中断
ET0=1; //使能总中断
}
DS18B20模块
思路:(4+5+数据处理指令)先定义输出脚 P14,再初始化,再读取温度
读温度函数:
(1) 初始化 DS18B20
(2) 跳过读取 ROM 指令(0xcc)
(3) 写转换指令(0x44)
(4) 延时 500us
(5) 再初始化 DS18B20
(6) 跳过读取 ROM 指令(0xcc)
(7) 写读取指令(0xbe)
(8) 先读低八位再读高八位
(9) 数据处理(整数/小数)
//onewire.h(官方所给驱动,无需记忆)
#ifndef _ONEWIRE_H
#define _ONEWIRE_H
//函数声明
unsigned char Read_DS18B20(void);
//需补全头文件
#endif
//--------------------------------------------------------------
//onewire.c(官方所给驱动,无需记忆)
sbit DQ = P1^4;
////单总线延时函数
void Delay_OneWire(unsigned int t)
{
unsigned char i;
while(t--){
for(i=0;i<12;i++); //扩大8-12倍
}
}
void Delay_us(void)
{
unsigned char i;
i = 30;
while (--i);
}
//通过单总线向DS18B20写一个字节
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(5);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(5);
}
//从DS18B20读取一个字节
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
// unsigned char index = 0;
for(i=0;i<8;i++)
{
DQ = 0;
dat >>= 1;
DQ = 1;
Delay_us();
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(5);
}
return dat;
}
//DS18B20初始化
bit init_ds18b20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80); // 延时大于480us
DQ = 1;
Delay_OneWire(10); // 14
initflag = DQ; // initflag等于1初始化失败
Delay_OneWire(5);
return initflag;
}
//DS18B20温度采集函数(自己写,需记忆)
unsigned int temp;
void rd_temperature(void)
{
uchar low,high;//定义变量
init_ds18b20();//复位初始化
Write_DS18B20(0XCC);//跳过ROM
Write_DS18B20(0X44);//开始温度转换
Delay_us(); //500us
init_ds18b20();//复位初始化
Write_DS18B20(0XCC);//跳过ROM
Write_DS18B20(0XBE);//依次读取数据
low=Read_DS18B20();//第一次读(温度低8位)
high=Read_DS18B20();//第二次读(温度高8位)
//整数显示
temp=high<<4;
temp=temp|(low>>4);
//小数显示
temp=high&0x0f;
temp<<=8;
temp=temp|low;
temp=temp*0.0625;
}
DS1302
思路:先定义 SCK,RST,SDA 脚;再写初始化函数;再读时间
//ds1302.h
#ifndef __DS1302_H
#define __DS1302_H
#include "reg52.h"
#include "intrins.h"
sbit SCK=P1^7;
sbit SDA=P2^3;
sbit RST = P1^3; // DS1302复位
#endif
//ds1302.c
#include "ds1302.h"
void Write_Ds1302_Byte(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++)
{
SCK=0;
SDA=temp&0x01;
temp>>=1;
SCK=1;
}
}
void Write_Ds1302( unsigned char address,unsigned char dat )
{
RST=0;
_nop_();
SCK=0;
_nop_();
RST=1;
_nop_();
Write_Ds1302_Byte(address);
Write_Ds1302_Byte(((dat/10)<<4)|(dat%10)); //修改dat为((dat/10)<<4)|(dat%10))
RST=0;
}
unsigned char Read_Ds1302 ( unsigned char address )
{
unsigned char i,temp=0x00;
uchar dat1,dat2;
RST=0;
_nop_();
SCK=0;
_nop_();
RST=1;
_nop_();
Write_Ds1302_Byte(address);
for (i=0;i<8;i++)
{
SCK=0;
temp>>=1;
if(SDA)
temp|=0x80;
SCK=1;
}
RST=0;
_nop_();
RST=0;
SCK=0;
_nop_();
SCK=1;
_nop_();
SDA=0;
_nop_();
SDA=1;
//新增代码(重要)
dat1=temp/16;
dat2=temp%16;
temp=dat1*10+dat2;
return (temp);
}
uchar Init_shijian[]={50,59,23,0,0,0,0}; //7个数据(秒,分,时,日,月,周,年)
uchar shijian[7];
void DS1302_Init() //DS1302初始化函数(需记忆)
{
unsigned char i,add=0x80;
Write_Ds1302(0x8e,0x00); //允许对任何的时钟或RAM寄存器进行写操作
for(i=0;i<7;i++)
{
Write_Ds1302(add,Init_shijian[i]);
}
Write_Ds1302(0x8e,0x80); //禁止对任何操作
}
void DS1302_Get() //DS1302读函数(需记忆)
{
unsigned char i,add=0x81;
Write_Ds1302(0x8e,0x00); //允许对任何的时钟或RAM寄存器进行写操作
for(i=0;i<7;i++)
{
shijian[i]=Read_Ds1302(add);
add=add+2;
}
Write_Ds1302(0x8e,0x80); //禁止对任何操作
}
IIC通信(PCF8591+AT24C02)
//iic.h
#ifndef _IIC_H
#define _IIC_H
void IIC_Start(void);
void IIC_Stop(void);
bit IIC_WaitAck(void);
void IIC_SendAck(bit ackbit);
void IIC_SendByte(unsigned char byt);
unsigned char IIC_RecByte(void);
#endif
//iic.c
#define DELAY_TIME 5
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
//总线引脚定义
sbit SDA = P2^1; /* 数据线 */
sbit SCL = P2^0; /* 时钟线 */
void IIC_Delay(unsigned char i)
{
do{_nop_();}
while(i--);
}
//总线启动条件
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 0;
IIC_Delay(DELAY_TIME);
SCL = 0;
}
//总线停止条件
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 1;
IIC_Delay(DELAY_TIME);
}
//发送应答
void IIC_SendAck(bit ackbit)
{
SCL = 0;
SDA = ackbit; // 0:应答,1:非应答
IIC_Delay(DELAY_TIME);
SCL = 1;
IIC_Delay(DELAY_TIME);
SCL = 0;
SDA = 1;
IIC_Delay(DELAY_TIME);
}
//等待应答
bit IIC_WaitAck(void)
{
bit ackbit;
SCL = 1;
IIC_Delay(DELAY_TIME);
ackbit = SDA;
SCL = 0;
IIC_Delay(DELAY_TIME);
return ackbit;
}
//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++)
{
SCL = 0;
IIC_Delay(DELAY_TIME);
if(byt & 0x80) SDA = 1;
else SDA = 0;
IIC_Delay(DELAY_TIME);
SCL = 1;
byt <<= 1;
IIC_Delay(DELAY_TIME);
}
SCL = 0;
}
//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
unsigned char i, da;
for(i=0; i<8; i++)
{
SCL = 1;
IIC_Delay(DELAY_TIME);
da <<= 1;
if(SDA) da |= 1;
SCL = 0;
IIC_Delay(DELAY_TIME);
}
return da;
}
//PCF8591
unsigned char AD_Read(unsigned char add)
{
uchar temp;
IIC_Start(); //IIC总线起始信号
IIC_SendByte(0x90); //PCF8591的写设备地址
IIC_WaitAck(); //等待从机应答
IIC_SendByte(add); //光敏传感器-0x01 电位器Rb2-0x03
IIC_WaitAck(); //等待从机应答
IIC_Stop(); //IIC总线停止信号
IIC_Start(); //IIC总线起始信号
IIC_SendByte(0x91); //PCF8591的读设备地址
IIC_WaitAck(); //等待从机应答
temp=IIC_RecByte(); //读取PCF8591通道x的数据
IIC_SendAck(0); //产生非应答信号
IIC_Stop(); //IIC总线停止信号
return temp;
}
void AD_Write(unsigned char dat)
{
IIC_Start(); //IIC总线起始信号
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x40);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
//AT24C02
unsigned char EEPROM_Read(unsigned char add)
{
uchar temp;
IIC_Start(); //IIC总线起始信号
IIC_SendByte(0xa0); //24C02的写设备地址
IIC_WaitAck(); //等待从机应答
IIC_SendByte(add); //光敏传感器-0x01 电位器Rb2-0x03
IIC_WaitAck(); //等待从机应答
IIC_Stop(); //IIC总线停止信号
IIC_Start(); //IIC总线起始信号
IIC_SendByte(0xa1); //24C02的读设备地址
IIC_WaitAck(); //等待从机应答
temp=IIC_RecByte(); //读取目标数据
IIC_SendAck(0); //产生非应答信号
IIC_Stop(); //IIC总线停止信号
}
void AD_Write(unsigned char dat)
{
IIC_Start(); //IIC总线起始信号
IIC_SendByte(0xa0); //24C02的写设备地址
IIC_WaitAck(); //等待从机应答
IIC_SendByte(add); //内存字节字节
IIC_WaitAck(); //等待从机应答
IIC_SendByte(dat); //写入目标数据
IIC_WaitAck(); //等待从机应答
IIC_Stop(); //IIC总线停止信号
}
超声波测距
实现步骤:
1、产生8个40KHz的超声波信号,通过TX引脚发射出去。
2、启动定时器,计算计数脉冲。
3、等待超声波信号返回,如果接收到反射回来的信号,RX引脚变为低电平。
4、停止定时器,读取脉冲个数,即获得时间T。
5、根据公式,L = V * T /2m,进行距离的计算。
void Timer1Init(void) //19 毫秒@11.0592MHz
{
TMOD |= 0x10;//工作模式 1
TH1 = 0;
TL1 = 0;
ET1 = 0;//关闭定时器 1 中断,直接当成计数使用
TR1 = 0;//关掉定时器 1
EA = 1;
}
void Send_Wave() //产生8个40KHx超声波信号
{
unsigned char i;
for(i = 0; i < 8; i++)
{
TX = 1;
Delay12us();
TX = 0;
Delay12us();
}
}
unsigned int GetDistance(void)
{
unsigned int Distance;
SendWave(); //发 8 个 40KHz 的方波
TR1 = 1; //打开计数器一
while((RX==1)&&(TF1==0)); //判断何时停止计数
TR1 = 0; //关闭计数器一
if(TF1==1)
{
TF1 = 0;
Distance = 0;
}
else
{
Distance = TH1;
Distance = (Distance << 8) | TL1;
Distance = Distance*17/1000;//放大 1000 倍方便显示单位为 cm
}
TH1 = TL1 = 0;
return Distance;
}
555 定时器
NE555电路是一个信号发生电路,其信号输出接到单片机的*P34*引脚,即单片机的*T0*引脚。 该信号的频率大小可以通过*Rb3可调电位器*改变。
计数的必须是定时器0,用于接收NE555产生的脉冲。
注意的是,要理解一下定时器系统各部分的定义,定时器0用于计数是TMOD为0X04。代码如下:
#include<STC15F2K60S2.H>
#include<intrins.h>
unsigned int count_freq,freq;
unsigned char t_1;
void Timer0Init(void);
void Timer1Init(void);
void main(){
allinit();
Timer0Init();Timer1Init();
EA=1;ET0=1;ET1=1;
while(1){
yi=10;er=10;san=10;si=10;wu=10;liu=freq/100;qi=freq%100/10;ba=freq%10;
display_12(yi,er);
display_34(san,si);
display_56(wu,liu);
display_78(qi,ba);
}
}
//定时器0用来计数
void time0() interrupt 1{
count_freq++;
}
//定时器1用来定时
void time1() interrupt 3{
t_1++;
if(t_1==200){
freq=count_freq;
count_freq=0;
t_1=0;
}
}
//定时器1定时5ms
void Timer1Init(void)
{
AUXR |= 0x40;
TMOD &= 0x0F;
TL1 = 0x00;
TH1 = 0x28;
TF1 = 0;
TR1 = 1;
}
//定时器0计数模式
void Timer0Init(void)
{
AUXR |= 0x80;
TMOD &= 0x0F;
TMOD |= 0x04;
TL0 = 0XFF;
TH0 = 0XFF;
TF0 = 0;
TR0 = 1;
}
PWM输出
void Init_Timer0()
{
TMOD = 0x01;
TH0 = (65535 - 1000) / 256;
TL0 = (65535 - 1000) % 256;
ET0 = 1;
EA = 1;
TR0 = 1;
}
void Service_Timer0() interrupt 1
{
TH0 = (65535 - 1000) / 256;
TL0 = (65535 - 1000) % 256;
if(stat_go == 0)
{
XBYTE[0x8000] = 0xe7;
return;
}
pwm++;
if(pwm <= pwm_duty)
{
XBYTE[0x8000] = ~(0x01 << stat);
}
else if(pwm <= 10)
{
XBYTE[0x8000] = 0xff;
}
else
{
XBYTE[0x8000] = ~(0x01 << stat);
pwm = 0;
if(key_puse == 0)
{
times++;
}
}
}
void LED_Control()
{
if(times == 5)
{
times = 0;
if(led_go == 0)
{
pwm_duty = pwm_duty + 1;
if(pwm_duty == 11)
{
pwm_duty = 10;
led_go = 1;
}
}
else if(led_go == 1)
{
pwm_duty = pwm_duty - 1;
if(pwm_duty == 255)
{
pwm_duty = 0;
led_go = 0;
if(stat_go == 1)
{
stat++;
if(stat == 8)
{
stat = 0;
}
}
else if(stat_go == 2)
{
stat--;
if(stat == 255)
{
stat = 7;
}
}
}
}
}
}
串口
void main()
{
UartInit();
EA=1;
ES=1;
}
void ser() interrupt 4 //串口中断
{
RI=0;
num=SBUF;
if(num=='$')
{
P2=0X80; P0=0X55;
}
}
void uart_tx(unsigned char *p,unsigned char length)
{
unsigned char i;
for(i=0;i<length;i++)
{
SBUF = *(p+i);
while(TI == 0);
TI = 0;
}
}
void send(unsigned char *p)
{
unsigned char index=0;
do
{
SBUF=p[index++];
while(TI == 0);
TI = 0;
}
while(p[index]!=0);
}
void UartInit(void) //[email protected]
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器1时钟为Fosc,即1T//0100 0000
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器//111 1110
TMOD &= 0x0F; //设定定时器1为16位自动重装方式
TL1 = 0xE0; //设定定时初值
TH1 = 0xFE; //设定定时初值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
}
标签:总结,char,temp,void,unsigned,蓝桥,IIC,0x0f
From: https://www.cnblogs.com/filosefer/p/17337495.html