蓝桥杯备赛的一些零碎笔记

1. 简化138译码器对对应芯片的使能

void Init138(unsigned char n)
{
	switch(n)
	{
		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;
	}
}

2.

void Delay(unsigned int time)
{
	while(time--);
	while(time--);
}

延时函数要用 unsigned int, 不用 unsigned char,因为int为两个字节,延时时间会长一些。

3.动态数码管的编写
(1)

void Display(unsigned char value, unsigned char pos)
{
	Init138(6);
	P0 = 0x01 << pos;
	Init138(7);
	P0 = value;
}

选择哪位数码管显示什么内容
(2)
定义年份的时候最好不定义为一个四位的大数,因为可能超过类型大小,最好分为两个unsigned char的两位数

unsigned char month = 0,num1 = 20, num2 = 18;

void  Display_Dongtai()
{
		Display(smg[num1/10], 0);
		Delay_smg(500);
		Display(smg[num1%10], 1);
		Delay_smg(500);
		Display(smg[num2/10], 2);
		Delay_smg(500);
		Display(smg[num2%10], 3);
		Delay_smg(500);
	
		Display(smg[16], 4);
		Delay_smg(500);
		Display(smg[16], 5);
		Delay_smg(500);
	
		Display(smg[month/10], 6);
		Delay_smg(500);
		Display(smg[month%10], 7);
		Delay_smg(500);
}

(3)
动态数码管显示变化的内容的时候,所用的延时函数和平常的延时也不一样

void delay(unsigned int t)
{
	while(t--)
	{
		 Display_Dongtai(); //在延时的同时也要执行当前数码管的状态
	}
}

void main()
{
	while(1)
	{
		Display_Dongtai();
		month++;
		if (month > 12)
		{
			month = 1;
			num2++;
		}
		delay(100);  //延时,体现数码管内容的变化
	}            
}

4.独立按键 (功能切换)

unsigned char flag = 0;

void KeyDown()
{
	
	if (key7 == 0)
	{
		delay(100);
		if (key7 == 0)                                                                                              
		{
			if(flag == 0)                                                                                    
			{
				led1 = 0;
				flag = 1;   //第一次按下后设置一个标志位
			}
			else if (flag == 1) //相当于是判断按键的第二次按下
			{
				led1 = 1;
				flag = 0;
			}	
				while(key7 == 0);//目的:使按键检测不那么快,按一下灯就亮,要不然按一下灯闪得很快
		}
	}
	
	if (key6 == 0)
	{
		delay(100);
		if (key6 == 0)
		{
				if (flag == 0) //key7按下后,key6不起作用,当然key6按下后,key7也不起作用,实现了功能选择
			{
				led2 = 0;
				flag = 2;
			}
			else if (flag == 2)
			{
				led2 = 1;
				flag = 0;
			}
			while(key6 == 0);
		}	
	}

5.中断系统
(1)中断服务函数里面尽量少做事,一些可做可不做的事情放出去做,例如可以在中断服务函数里面做一个标志位的转化,把要做的功能引出去。

unsigned char flag = 0;

void ServiceInit0() interrupt 0
{
	flag = 1;
}

void Ledint()
{
	if (flag == 1)
	{
		led8 = 0;
		delay(60000);
		led8 = 1;
	}
}

void Working()
{
	led1 = 0;
	delay(60000);
	led1 = 1;
}

void main()
{
	while(1)
	{
		Working();
		Ledint();//类似于轮询的方法,即使检测到flag=1,也要等Working()函数执行完才执行Ledint()。
	}
}

6.寄存器定时器
在这里插入图片描述
7.PWM(通过按键改变led的亮度)

unsigned char flag = 0;
void keydown()
{
	if (key7 == 0)
	{
		delay(100);
		if (key7 == 0)
		{
			switch (flag)
			{
				case 0: 
					ledvalue = 10;
					 TR0 = 1; //在按键第一次按下的时候再开启计数功能
					 flag = 1;
				 break;
				 
				case 1: 
					ledvalue = 50; 
					flag = 2; 
				break;
				
				case 2:
					 ledvalue = 90; 
				 	flag = 3;
				  break;
				  
				case 3: 
					led1 = 1; 
					TR0 = 0; 
					flag = 0; 
				break;
			}
			while(key7 == 0);
		}
	}
}

void InitTime0() //此项目要求PWM频率为100HZ(周期为10ms=10000us),将其分为百分制,所以100*100,统一将定时器定时为100us
{
	TMOD = 0x01;
	TH0 = (65535 - 100) / 256;
	TL0 = (65535 - 100) % 256;
	
	ET0 = 1;
	EA  = 1;
	        //不急开启计数功能
}

void ServerTime0() interrupt 1
{
	TH0 = (65535 - 100) / 256;
	TL0 = (65535 - 100) % 256;
	
	count++;
	if (count == ledvalue)
	{
		led1 = 1;//到达设定值时,紧接着进入低电平阶段,执行相对无效状态(led灭)
	} 
	if (count == 100)//一个周期结束马上回到高电平,所以在高电平期间执行有效状态(在此处就是led亮的时间)
	{
		led1 = 0;//执行有效状态
		count = 0;
	}
}
void main()
{
	InitTime0();
	HC138_4();
	led1 = 1;
	while(1)
	{
		keydown();
	}
}

8.串口收发

#include <REGX52.H>

sfr AUXR = 0x8e;//蓝桥杯板子新增寄存器。需要新定义下

unsigned char uart_dat;
 
void uart_init()
{
	TMOD = 0x20;//八位自动重装载模式
	TH1 = 0xfd;//设置波特率为9600
	TL1 = 0xfd;
	TR1 = 1;//启动定时器1
	
	SCON = 0x50;//串口参数为模式1和允许接收
	AUXR = 0x00;//记住就行,难得解释
	
	ES = 1;//使能串口中断
	EA = 1;//使能总中断
}
 
void Uart_send(unsigned char dat)
{
	SBUF = dat;
	while(TI == 0);//等待发送数据完成(发送完成后TI = 1)
	TI = 0;//清除发送完成标志
}

void ServerTime() interrupt 4
{ //在串口中断里面接收串口数据
	if (RI == 1)
	{
		RI = 0;
		uart_dat = SBUF;
		
		Uart_send(uart_dat+1);
	}
}


int main()
{
	uart_init();
	Uart_send(0x88);
	while(1);
}

在这里插入图片描述

发送字符串:

void SendByte(unsigned char dat)
{
	SBUF = dat;
	while(TI == 0);
	TI = 0;
}	
		
void SendString(unsigned char *dat)
{
	while(*dat != '\0')
	{
		SendByte(*dat++);
	}
}

SendString("Welcome to XMF System!\r\n");

9.IO扩展与存储器映射扩展

存储器映射扩展:
在这里插入图片描述
在这里插入图片描述
IO口扩展:

void Init138(unsigned char n)
{
	switch(n)
	{
		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;
	}
}
Init138(4);
P0 = 0xf0;
可以替代为:
XBYTE[0x8000] = 0xf0;

10.DS18B20
在这里插入图片描述在这里插入图片描述

#include <REGX52.H>
#include "onewire.h"   
#include "absacc.h"  //要用寄存器映射扩展就得用此头文件  
//XBYTE[0x8000] = LED灯控制、  XBYTE[0xa000] = 蜂鸣器继电器控制
 //XBYTE[0xc000] = 数码管位选、 XBYTE[0xe000] = 数码管段选
 
unsigned int T_dat = 0;

data unsigned char SMGNODot[10] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
data unsigned char SMGDot[10]   = {0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};      //共阳

void DelaySMG(unsigned int t)
{
	while(t--);
}

void Display_SMG(unsigned char pos, unsigned char value)
{
	XBYTE[0xe000] = 0xff;     //消影
	XBYTE[0xc000] = 0x01 << pos;
	XBYTE[0xe000] = value;
}

void Close_All_SMG()
{
	XBYTE[0xc000] = 0xff;
	XBYTE[0xe000] = 0xff;
}

void Display_ALL()
{
	Display_SMG(7, SMGNODot[T_dat % 10]);      
	DelaySMG(400);
	Display_SMG(6, SMGDot[(T_dat % 100) / 10]);      
	DelaySMG(400);
	Display_SMG(5, SMGNODot[T_dat / 100]);      
	DelaySMG(400);
	
	Display_SMG(4, 0xff);      
	DelaySMG(400);
	Display_SMG(3, 0xff);      
	DelaySMG(400);
	Display_SMG(2, 0xff);      
	DelaySMG(400);
	Display_SMG(1, 0xff);      
	DelaySMG(400);
	Display_SMG(0, 0xff);      
	DelaySMG(400);
	
	Close_All_SMG();
}

void Delay_DS18B20(unsigned int t)
{
	while(t--)
	{
		Display_ALL();
	}
}
void Read()
{
	unsigned char LSB, MSB;
	
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);
	Delay_DS18B20(1000);
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe);
	LSB = Read_DS18B20();
	MSB = Read_DS18B20();
	init_ds18b20();
	
	T_dat = 0x0000;
	T_dat = MSB;          //temp是16位int整型,msb、lsb是8为char型
	T_dat <<= 8;
	T_dat = T_dat | LSB;   //整合到一起
	
	if((T_dat & 0xf800) == 0x0000)    //正温度的处理办法  与高五位进行判断
	{
		T_dat >>= 4;          //取出温度结果的整数部分        右移四位,将小数移出去
		T_dat = T_dat * 10;    //放大10倍,然后加上小数部分
		T_dat = T_dat + (LSB & 0x0f) * 0.625;                  // 取LSB的低四位(小数位)、分辨率0.0625也放大十倍
	}
}
void main()
{
	XBYTE[0x8000] = 0xff;
	while(1)
	{
		Read();
		Display_ALL();
	}
}
举一个例子说明这个处理的具体过程:
假设DS18B20的温度采样结果是:LSB = 0x96,MSB = 0x01。
温度数据变量T_dat为16位无符号int整型,初始值为0x0000。
执行T_dat = MSB;语句后, T_dat 的值为:0x0001。
执行T_dat <<= 8;语句后, T_dat 的值为:0x0100。
执行T_dat = T_dat | LSB;语句后, T_dat 的值为:0x0196。
通过高5位的符号扩展位判断,进行正温度的处理算法,正常来说,应该是:
T_dat = 0x0196 × 0.0625 = 406 × 0.0625 = 25.375 摄氏度。

如果要求温度结果保留1位小数,为了简化在单片机中的运算,可以放大10倍进行整型处理:
首先将温度结果的整数部分取出: T_dat >>= 4;即 T_dat = 0x0019 = 25。
然后将整数部分放大10倍: T_dat = T_dat × 10 ;即 T_dat = 250。
然后将小数部分取出: LSB&0x0f,其结果为0x06。
再将小数部分乘以0.0625的10倍,即0x06 × 0.625 = 3.73。
最后将整数部分和小数部分相加: T_dat = 250 + 3.73 = 253。为什么?因为 T_dat 是整型。
对于温度数据253,在数码管显示的时候,在十位出加上一个小数点,就变成了:25.3。
这样可以让单片机避免很多浮点运算,而且数码管显示也会很简洁很方便。

如果要求温度结果只显示整数部分,那就不用这么啰嗦,直接显示整数部分即可:
T_dat >>= 4;即 T_dat = 0x0019 = 25 摄氏度。

11.DS1302
在这里插入图片描述在这里插入图片描述在这里插入图片描述12.NE555定时器
在这里插入图片描述

#include <REGX52.H>
#include "smg.h"

unsigned int count_f;
unsigned char count_t;
unsigned int dat;

//**********************************************************************************************
void Init_Timer()
{
	//定时器0用作计数,8位自动重装载
	TH0 = 0xff;                     //来一次脉冲就溢出,P34:T0 定时/计数器0外部事件计数输入引脚
	TL0 = 0xff;                     //P34与555定时器的single端连接在一起
	
	//定时器1用作计时,50ms
	TH1 = (65535 - 50000) / 256;
	TL1 = (65535 - 50000) % 256;	
	
	TMOD = 0x16;                    //0001 0110
	
	ET0 = 1;
	ET1 = 1;
	EA  = 1;
	
	TR0 = 1;
	TR1 = 1;
}

void Servece_Time0() interrupt 1
{
	count_f++;                    //来一个脉冲中断一次
}

void Servece_Time1() interrupt 3
{
	TH1 = (65535 - 50000) / 256;
	TL1 = (65535 - 50000) % 256;
	
	count_t++;
	if (count_t == 20)
	{
		count_t = 0;
		dat = count_f;             //dat保存之前值,又开始一轮新的计数
		count_f = 0;
	}
}
//**********************************************************************************************

void Display()
{
  Display_smg(0, 0x8e);
	Delay(100);
	Display_smg(1, 0xff);
	Delay(100);
	Display_smg(2, 0xff);
	Delay(100);
	
	if (dat > 9999)                          //数字长度不足5位时,熄灭处理未用到的数码管
	{
		Display_smg(3, smg[dat / 10000]);
		Delay(100);
	}
	
	if (dat > 999)                           //数字长度不足5位时,熄灭处理未用到的数码管
	{
		Display_smg(4, smg[(dat / 1000) % 10]);
		Delay(100);
	}
	
	if (dat > 99)                            //数字长度不足5位时,熄灭处理未用到的数码管
	{
		Display_smg(5, smg[(dat / 100) % 10]);
		Delay(100);
	}
	
	if (dat > 9)                             //数字长度不足5位时,熄灭处理未用到的数码管
	{
		Display_smg(6, smg[(dat / 10) % 10]);
		Delay(100);
	}
	
	Display_smg(7, smg[dat % 10]);
	Delay(100);
	
	Display_ALL(0xff);
	
}
	
void main()
{  
	Init_Timer();
	while(1)
	{
		Display();
	}
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值