【蓝桥杯】单片机组常用基础模块总结

文章目录

  • 前言
    • 总结了一些蓝桥杯单片机基础的模块。教程可参考小蜜蜂老师的单片机课程。下面是老师课程的链接。 [【历届蓝桥杯单片机省赛真题考点归纳】](https://bbs.21ic.com/icview-2480602-1-1.html)
  • 一、基础模块
    • 1.基本模板
    • 2.外部中断0
    • 3.定时器0
    • 4.串口(以定时器1为时钟源)
    • 5.温度传感器
    • 6.实时时钟(秒分时日月周年,BCD码计数)
    • 7.ADC
    • 8.EEPROM(设备地址 0xA0)
    • 9.矩阵按键
    • 10.超声波
    • 11.频率测量(555定时器Rb3调节频率)
    • 12.模拟PWM(选取一个PWM周期)
  • 总结


前言

总结了一些蓝桥杯单片机基础的模块。教程可参考小蜜蜂老师的单片机课程。下面是老师课程的链接。
【历届蓝桥杯单片机省赛真题考点归纳】

一、基础模块

1.基本模板

#include "reg52.h"
#include "iic.h"
#include "onewire.h"//关于延时的函数里的参数乘以10
#include "intrins.h"//内含nop,超声波用到
#include "ds1302.h"//时间数据采用BCD码
//iic.h里的 _IIC_H ==> __IIC_H  
//onewire 涉及延时的参数*10,函数未在头文件声明

typedef unsigned char uint8;
typedef unsigned int uint32;

#define LED_Channel  		4
#define BEEP_DELAY_Channel  5
#define COM_Channel  		6
#define SMG_Channel  		7

sfr P4 = 0xc0;
sfr AUXR = 0x8e;
//超声波接口
sbit TX = P1^0;
sbit RT = P1^1;
//数码管编码
uint8 code TAB[18] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xbf,0x7f};
//带小数点
uint8 code Dot_TAB[16]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0x08,0x03,0x46,0x21,0x06,0x0e} ;
//矩阵按键接口  J5:12
sbit R1 = P3^0;
sbit R2 = P3^1;
sbit R3 = P3^2;
sbit R4 = P3^3;

sbit C1 = P4^4;
sbit C2 = P4^2;
sbit C3 = P3^5;
sbit C4 = P3^4;
//独立按键   J5:23
sbit S4 = P3^3;
sbit S5 = P3^2;
sbit S6 = P3^1;
sbit S7 = P3^0;
//自定义变量
uint8 node //显示界面编号
uint32 temp//读取温度
uint8 cnt_f//频率计数
void Delay(uint32 ms)
{
	uint32 x,y;
	for(x=0;x<ms;x++)
		for(y=846;y>0;y--){}
}
void InitHC138(uint8 Channel)
{
	switch(Channel)
	{
		case 4:P2 = (P2 & 0x1f) | 0x80;break;
		case 5:P2 = (P2 & 0x1f) | 0xa0;break;
		case 6:P2 = (P2 & 0x1f) | 0xc0;break;
		case 7:P2 = (P2 & 0x1f) | 0xe0;break;
		default:P2 &= 0x1f;
	}
}
void Init_System(void)
{
	InitHC138(BEEP_DELAY_Channel);
	P0 = 0x00;
	InitHC138(LED_Channel);
	P0 = 0xff;
	InitHC138(0);
}

void Display_Bit(uint8 pos,uint8 date)
{
	InitHC138(COM_Channel);
	P0 = 0x01<<pos;
	InitHC138(SMG_Channel);
	P0 = date;
	InitHC138(0);
}
void Display_All(uint8 date)
{
	InitHC138(COM_Channel);
	P0 = 0xff;
	InitHC138(SMG_Channel);
	P0 = date;
	InitHC138(0);
}
void Dislpay(uint8 node)//第十二届省赛数码管显示代码
{
	switch(node)
	{
		case 0:
			Display_Bit(0,TAB[12]),Delay(1);
			Display_Bit(1,0xff),Delay(1);
			Display_Bit(2,0xff),Delay(1);
			Display_Bit(3,0xff),Delay(1);
			Display_Bit(4,TAB[temp/1000]),Delay(1);
			Display_Bit(5,Dot_TAB[(temp%1000)/100]),Delay(1);
			Display_Bit(6,TAB[(temp%100)/10]),Delay(1);
			Display_Bit(7,TAB[temp%10]),Delay(1);
			Display_All(0xff);
			break;
		case 1:
			Display_Bit(0,TAB[18]),Delay(1);
			Display_Bit(1,0xff),Delay(1);
			Display_Bit(2,0xff),Delay(1);
			Display_Bit(3,0xff),Delay(1);
			Display_Bit(4,0xff),Delay(1);
			Display_Bit(5,0xff),Delay(1);
			Display_Bit(6,TAB[default_temp/10]),Delay(1);
			Display_Bit(7,TAB[default_temp%10]),Delay(1);
			Display_All(0xff);
			break;
		case 2:
			if(mode == 0)
			{
				Display_Bit(0,TAB[10]),Delay(1);
				Display_Bit(1,0xff),Delay(1);
				Display_Bit(2,0xff),Delay(1);
				Display_Bit(3,0xff),Delay(1);
				Display_Bit(4,0xff),Delay(1);
				Display_Bit(5,Dot_TAB[Vdac]),Delay(1);
				Display_Bit(6,TAB[0]),Delay(1);
				Display_Bit(7,TAB[0]),Delay(1);
				Display_All(0xff);
			}
			else
			{
				Display_Bit(0,TAB[10]),Delay(1);
				Display_Bit(1,0xff),Delay(1);
				Display_Bit(2,0xff),Delay(1);
				Display_Bit(3,0xff),Delay(1);
				Display_Bit(4,0xff),Delay(1);
				Display_Bit(5,Dot_TAB[Vdac/100]),Delay(1);
				Display_Bit(6,TAB[(Vdac%100)/10]),Delay(1);
				Display_Bit(7,TAB[Vdac%10]),Delay(1);
				Display_All(0xff);
			}
			
			break;
		default:Display_All(0xff);break;
	}
}
void SMG_Delay(uint32 t)
{
	while(t--)
	{
		Dislpay(node);
	}
}

2.外部中断0

//P32 INT0  P33 INT1
//J5  23:独立按键
void INT0_Init()
{
	IT0 = 1;//下降沿
	EX0 = 1;
	EA  = 1;
}

3.定时器0

void Timer0Init(void)   // 10 毫秒 @11.0592MHz
{
	AUXR &= 0x7F;	// 定时器时钟 12T 模式  FOSC/12  65.536ms
	TMOD &= 0xF0;	// 设置定时器模式
	TL0 = 0x00;		// 设置定时初值
	TH0 = 0xDC;		// 设置定时初值
	TF0 = 0;		// 清除 TF0 标志
	TR0 = 1;		// 定时器 0 开始计时
	
	ET0 = 1;
	EA = 1;
}
void Time0_Hander() interrupt 1
{
	//可将读取温度,adc采集的标志放入中断,提高效率
}

4.串口(以定时器1为时钟源)

void UartInit(void)		//[email protected]
{
	SCON = 0x50;	// 8位数据,可变波特率
	AUXR |= 0x40;	// 定时器1时钟为Fosc,即1T
	AUXR &= 0xFE;	// 串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;	// 设定定时器1为16位自动重装方式
	TL1 = 0xE0;		// 设定定时初值
	TH1 = 0xFE;		// 设定定时初值
	ET1 = 0;		// 禁止定时器1中断
	TR1 = 1;		// 启动定时器1
	ES = 1;         // 允许串口中断
	EA = 1;         // 开启总中断
}
void Send_Byte(uint8 date)
{
	SBUF = date;
	while(TI == 0){}
	TI = 0;
	
}
void Uart_Hander(void) interrupt 4
{
	if(RI == 1)
	{
		RI = 0;
		getdate = SBUF;
		Send_Byte(getdate);
	}
}

5.温度传感器

初始化 0xcc 0x44 延时
初始化 0xcc 0xbe 读取

第一种方式

//初始化,跳过rom,操作
//前5位是符号位,后4位是小数位,小数存放在LSB(低位先读),//0.0625*10
void Read_Temp(void)
{
	uint8 LSB,MSB;
	
	init_ds18b20();
	Write_DS18B20(0xcc);  //跳过ROM指令
	Write_DS18B20(0x44);	//开始温度转换
	SMG_Delay(50);
	//可用 Delay_OneWire(200);	   // 延时一段时间
	
	init_ds18b20();
	Write_DS18B20(0xcc);	//跳过ROM指令
	Write_DS18B20(0xbe);	//读取高速暂存器
	
	LSB =Read_DS18B20();  //读取第一个字节
	MSB =Read_DS18B20();	//读取第二字节

	temp = (MSB<<8)|LSB;
	
	//包含小数 ,如果不包含小数,直接将temp右移4位即可
	if((temp & 0xf800)== 0x0000)  //判断高五位符号位是否为0 ,即是否为证书
	{
		temp = temp>>4;
		temp = temp * 10;
		temp = temp + (LSB & 0x0f)*0.625 ;//0.0625*10
	}
}

第二种方式

uint32 Read_Temp(void)
{
	uint8 LSB,MSB;
	uint32 temp;
	init_ds18b20();
	Write_DS18B20(0xcc);  //跳过ROM指令
	Write_DS18B20(0x44);	//开始温度转换
	//SMG_Delay(50);
	Delay_OneWire(200);	   // 延时一段时间
	
	init_ds18b20();
	Write_DS18B20(0xcc);	//跳过ROM指令
	Write_DS18B20(0xbe);	//读取高速暂存器
	
	LSB =Read_DS18B20();  //读取第一个字节
	MSB =Read_DS18B20();	//读取第二字节
	temp= ((MSB&0x0f)<<8)| LSB;
	return temp;
}
temperature = Read_Temp()*0.0625;

6.实时时钟(秒分时日月周年,BCD码计数)

允许写0x8E,0x00
操作
禁止写0x8E,0x80

//定义DS1302写操作的日历时钟存储器地址
uint8 Write_DS1302_addr[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
//定义DS1302读操作的日历时钟存储器地址
uint8 Read_DS1302_addr[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
uint8 time[7] = {0x30,0x12,0x08,0x10,0x01,0x03,0x21}//21年3周1月10日8点12分30秒
//十位数 time[i]/16 个位数 time[i]%16
void DS1302_Init(void)
{
	uint8 n;
	Write_Ds1302_Byte(0x8E,0x00);//允许写
	for(n=0;n<7;n++)
	{
		Write_Ds1302_Byte(Write_DS1302_addr[n],Timer[n]);
	}
	Write_Ds1302_Byte(0x8E,0x80);//禁止写
}
void Read_DS1302_Time(void)
{
	uint8 n;
	for(n=0;n<7;n++)
	{
		Timer[n] = Read_Ds1302_Byte ( Read_DS1302_addr[n]);
	}
}


7.ADC

PCF8951 地址 0x90
可调电阻Rb2 0x03
LM32 0x02(差分输入)
光敏电阻 0x01
外部引脚 0x00

uint8 Read_ADC(uint8 ch)  //可调电阻rb2
{
	uint8 date;
	IIC_Start();					//IIC总线起始信号					
	IIC_SendByte(0x90); 	//PCF8591的写地址  读地址为0x91
	IIC_WaitAck();				//等待从机应答	
	IIC_SendByte(ch);		//写入PCF8591的控制字节	
	IIC_WaitAck(); 				//等待从机应答	
	
	IIC_Start();					//IIC总线起始信号					
	IIC_SendByte(0x91); 	//PCF8591的读设备地址
	IIC_WaitAck();				//等待从机应答	
	date= IIC_RecByte();	//读取目标数据
	IIC_SendAck(1); 			//产生非应答信号		
	IIC_Stop();						//IIC总线停止信号			
	
	return date
}
void DAC(uint8 date)	// 输入值需要转换
{
	IIC_Start();
	IIC_SendByte(0x90);		
	IIC_WaitAck();				
	IIC_SendByte(0x40);
	IIC_WaitAck();
	IIC_SendByte(date);
	IIC_WaitAck();
	IIC_Stop();
}

8.EEPROM(设备地址 0xA0)

读取一个字节要Delay(10);

void WriteByte(uint8 addr, uint8 date)
{
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(addr);
	IIC_WaitAck();
	IIC_SendByte(date);
	IIC_WaitAck();
	IIC_Stop();
}

uint8 ReadByte(uint8 addr)
{
	uint8 date;
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(addr);
	IIC_WaitAck();
	IIC_Start();
	IIC_SendByte(0xa0 | 0x01);
	IIC_WaitAck();
	date = IIC_RecByte();
	IIC_Ack(1);
	IIC_Stop();
	return date;
}

9.矩阵按键

void Key_Scan()
{
	R1=0,R2=1,R3=1,R4=1;
	C1=1,C2=1,C3=1,C4=1;
	if(C1==0)
	{
		Delay(10);
		if(C1==0)
		{
			while(C1==0);
		}
	}
	if(C2==0)
	{
		Delay(10);
		if(C2==0)
		{
			while(C2==0);
		}
	}
	if(C3==0)
	{
		Delay(10);
		if(C3==0)
		{
			while(C3==0);
		}
	}
	if(C4==0)
	{
		Delay(10);
		if(C4==0)
		{
			while(C4==0);
		}
	}
	
	
	R1=1,R2=0,R3=1,R4=1;
	C1=1,C2=1,C3=1,C4=1;
	if(C1==0)
	{
		Delay(10);
		if(C1==0)
		{
			while(C1==0);
		}
	}
	if(C2==0)
	{
		Delay(10);
		if(C2==0)
		{
			while(C2==0);
		}
	}
	if(C3==0)
	{
		Delay(10);
		if(C3==0)
		{
			while(C3==0);
		}
	}
	if(C4==0)
	{
		Delay(10);
		if(C4==0)
		{
			while(C4==0);
		}
	}
	
	
	R1=1,R2=1,R3=0,R4=1;
	C1=1,C2=1,C3=1,C4=1;
	if(C1==0)
	{
		Delay(10);
		if(C1==0)
		{
			while(C1==0);
		}
	}
	if(C2==0)
	{
		Delay(10);
		if(C2==0)
		{
			while(C2==0);
		}
	}
	if(C3==0)
	{
		Delay(10);
		if(C3==0)
		{
			while(C3==0);
		}
	}
	if(C4==0)
	{
		Delay(10);
		if(C4==0)
		{
			while(C4==0);
		}
	}
	
	
	R1=1,R2=1,R3=1,R4=0;
	C1=1,C2=1,C3=1,C4=1;
	if(C1==0)
	{
		Delay(10);
		if(C1==0)
		{
			while(C1==0);
		}
	}
	if(C2==0)
	{
		Delay(10);
		if(C2==0)
		{
			while(C2==0);
		}
	}
	if(C3==0)
	{
		Delay(10);
		if(C3==0)
		{
			while(C3==0);
		}
	}
	if(C4==0)
	{
		Delay(10);
		if(C4==0)
		{
			while(C4==0);
		}
	}
}


10.超声波

void Timer1Init(void)		//10微秒@11.0592MHz
{
	TMOD &= 0x0F;		//设置定时器模式
//	AUXR |= 0x40;		//定时器时钟1T模式
//	TL1 = 0x91;		//设置定时初始值
//	TH1 = 0xFF;		//设置定时初始值
//	TF1 = 0;		//清除TF1标志
//	TR1 = 1;		//定时器1开始计时
}
void Delay12us()		//@11.0592MHz
{
	unsigned char i;

	_nop_();
	_nop_();
	_nop_();
	i = 30;
	while (--i);
}

void Send_Wave(void)
{
	uint8 i=0;
	for(i=0;i<8;i++)
	{
		TX = 1;
		Delay12us();
		TX = 0;
		Delay12us();
	}
}
void Measure_Distance(void)
{
	AUXR |= 0x40;		//定时器时钟1T模式
	TL1 = 0x00;		//设置定时初始值
	TH1 = 0x00;		//设置定时初始值
	TF1 = 0;		//清除TF1标志
	Send_Wave();
	TR1 = 1;		//定时器1开始计时
	
	while((RT==1)&&(TF1==0));
	TR1 = 0;
	if(TF1 == 1)
	{
		distance = 999;
		TF1 = 0;
	}
	else
	{
		time = TH1;
		time = (time<<8)|TL1;
		distance = time*0.017/11.0592//(f);
	}
}

11.频率测量(555定时器Rb3调节频率)

void Init_Timer01(void)
{
	TMOD = 0x16;
	TH0 = 0xff;
	TL0 = 0xff;
	
	TH1 = (65536-50000)/256;
	TL1 = (65536-50000)%256;
	
	TR0 = 1;
	ET0 = 1;
	
	TR1 = 1;
	ET1 = 1;
	
	EA  = 1;
}
void Timer0_Service() interrupt 1
{
	cnt_f ++;
}

void Timer1_Service() interrupt 3
{
	TH1 = (65536 - 50000)/256;
	TL1 = (65536 - 50000)%256;
	
	cnt_t ++;
	if(cnt_t == 20)
	{
		cnt_t = 0;
		dat = cnt_f;
		cnt_f = 0;	
	}
}
void Init_TF0(void)
{
	TMOD = 0x01;
	//0.1ms
	TH0 = (65536 - 100) / 256;
	TL0 = (65536 - 100) % 256;
	ET0 = 1;
	EA = 1;
	TR0 = 0;
}
void TF0_Hander(void) interrupt 1
{
	TH0 = (65536 - 100) / 256;
	TL0 = (65536 - 100) % 256;
	cnt++;
	if(cnt <= cmp)
	{
		InitHC138(LED_Channel);
		P0 = 0xfe;
	}
	else if(cnt <100)
	{
		InitHC138(LED_Channel);
		P0 = 0xff;
	}
	else 
	{
		cnt = 0;
		InitHC138(LED_Channel);
		P0 = 0xff;
	}
	
}

12.模拟PWM(选取一个PWM周期)

void Init_TF0(void)
{
	TMOD = 0x01;
	//0.1ms
	TH0 = (65536 - 100) / 256;
	TL0 = (65536 - 100) % 256;
	ET0 = 1;
	EA = 1;
	TR0 = 0;
}
void TF0_Hander(void) interrupt 1
{
	TH0 = (65536 - 100) / 256;
	TL0 = (65536 - 100) % 256;
	cnt++;
	if(cnt <= cmp)
	{
		InitHC138(LED_Channel);
		P0 = 0xfe;
	}
	else if(cnt <100)
	{
		InitHC138(LED_Channel);
		P0 = 0xff;
	}
	else 
	{
		cnt = 0;
		InitHC138(LED_Channel);
		P0 = 0xff;
	}
	
}

总结

先这样吧,有错误再改,后续看看能不能把历届省赛的代码贴出来。

你可能感兴趣的:(蓝桥杯,算法,硬件工程)