蓝桥杯单片机学习记录5——第10届省赛真题练习
前言
上一篇我们练习了第11届的两道省赛题,都没有什么难度,主要是为了练习AD/DA,DS18B20和AT24C02的使用方法及调试。
这次我们接着来练习第10届的省赛题,这一届的题目也不难,同样用了AD/DA,但这次主要是练习NE555的使用方法。
赛题要求
硬件框图
功能要求
- 频率显示界面
- 电压显示界面
- 按键功能
- LED 指示灯功能
- 初始状态说明
- 初始状态上电默认处于电压测量状态,数码管显示和 LED 指示功能启用。
- 初始状态上电默认 PCF8591 DAC 芯片输出固定电压值 2.0V。
设计思路
功能逻辑框图
实现代码框图
不管是功能逻辑还是代码框架,逻辑瞬间清晰,知道该干什么了吧!XD
实现代码
main.c
#include <STC15F2K60S2.H>
#include "hardware.h"
#include "iic.h"
static u32 adc,dac; //模数转换后的值,取值0~500,数模转换的输入值,0~255
u32 NE_f=0, count_f=0,Page=1; //获取的NE555的频率,页码
u8 Key,led; //获取的按键,LED的状态量
bit StateFlag=0,VFlag=0,LEDFlag=0,SEGFlag=0; //状态标志位,电压输出模式标志位,LED显示标志位,数码管显示标志位
void main()
{
InitInterrupt(); //中断初始化
P_Init(); //P0控制外设初始化
while(1)
{
Data_Task();
Key_Task();
Logic_Task();
Display();
}
}
- NE555
void InitInterrupt(void)
{
TMOD = 0x16; //0001 0110 定时器0配置为8位自动重装载计数器,定时器1配置为50ms中断一次
TH0 = 0xFF; //定时器0
TL0 = 0xFF;
TH1 = (65535 - 49999) / 256; //定时器1
TL1 = (65535 - 49999) % 256;
ET0 = 1;
ET1 = 1;
TR0 = 1;
TR1 = 1;
EA = 1;
}
void Timer0() interrupt 1
{
NE_f++; //触发后频率计数加1
}
void Timer1() interrupt 3
{
static u8 cnt = 0;
TH1 = (65535 - 49999) / 256;
TL1 = (65535 - 49999) % 256;
++cnt;
if(cnt>=20)
{
count_f = NE_f; //转递频率值
NE_f = 0; //复位
cnt = 0;
}
}
- 获取数据函数
void Data_Task(void)
{
adc = PCF_ADC(); //获取数字量
adc = adc*100/51; //调整为0~500
Key = Get_Key(); //获取键值
}
- 按键任务函数
void Key_Task(void) //按下按键后,相应标志位取反
{
if(Key == 1)
{
StateFlag = ~StateFlag;
}
if(Key == 2)
{
VFlag = ~VFlag;
}
if(Key == 3)
{
LEDFlag = ~LEDFlag;
}
if(Key == 4)
{
SEGFlag = ~SEGFlag;
}
}
-逻辑任务函数
void Logic_Task(void)
{
if(StateFlag) {Page = 2;} //页码为频率
else {Page = 1;} //页码为电压
if(VFlag) //标志位为1时,数模转换的输入值读取模数转换后的值再转换成模拟量输出
{
dac = PCF_ADC();
DAC(dac);
}
else {DAC(108);} //固定输出2.0V的模拟量
if(LEDFlag) {led &= ~0x1f;LED_Task(led);} //当标志位为1时,LED显示熄灭
else {LED_Logic();} //为0时,LED显示开启
}
//LED显示逻辑函数
void LED_Logic(void) //led状态值的操作在上一篇讲过,这里就不解释了
{
if(StateFlag) {led |= 0x02;led &= ~0x01;} //频率页面时L2点亮,L1熄灭
else {led |= 0x01;led &= ~0x02;} //电压页面L1点亮,L2熄灭
if(adc>=350) {led |= 0x04;}
else if (adc>=250&&adc<350) {led &= ~0x04;}
else if (adc>=150&&adc<250) {led |= 0x04;}
else if (adc<150) {led &= ~0x04;}
if(count_f>=10000) {led |= 0x08;}
else if(count_f>=5000&&count_f<10000) {led &= ~0x08;}
else if(count_f>=1000&&count_f<5000) {led |= 0x08;}
else if(count_f<1000) {led &= ~0x08;}
if(VFlag) {led |= 0x10;}
else {led &= ~0x10;}
LED_Task(led);
}
void LED_Task(u8 led)
{
P0 = ~led;
_138_Task(4); //锁存器操作,可以和我的不一样
_138_Task(0);
}
- 数码管显示任务函数
void Display(void)
{
if(SEGFlag) //标志位为1,数码管显示熄灭
{
Nixie(8,22);
}
else if(SEGFlag==0)
{
switch(Page) //1:电压页面,2:频率页面
{
case 2:
Nixie(1,20);
if(!(count_f/10000%10)) Nixie(4,22);
else
Nixie(4,count_f/10000%10);
if(!(count_f/1000%10)&&!(count_f/10000%10)) Nixie(5,22);
else
Nixie(5,count_f/1000%10);
if(!(count_f/1000%10)&&!(count_f/100%10)&&!(count_f/10000%10)) Nixie(6,22);
else
Nixie(6,count_f/100%10);
if(!(count_f/10%10)&&!(count_f/100%10)&&!(count_f/10000%10)) Nixie(7,22);
else
Nixie(7,count_f/10%10);
Nixie(8,count_f%10);
break;
case 1:
Nixie(1,21);
Nixie(6,(adc/100%10)+10);
Nixie(7,adc/10%10);
Nixie(8,adc%10);
break;
}
}
}
AD/DA
//IIC的驱动代码直接拿官方给的,这里不做展示
void DAC(unsigned char dat) //数字量转换为模拟量
{
bit Ack;
IIC_Start();
IIC_SendByte(0x90);
Ack = IIC_WaitAck();
IIC_SendByte(0x40);
Ack = IIC_WaitAck();
IIC_SendByte(dat);
Ack = IIC_WaitAck();
IIC_Stop();
}
unsigned char PCF_ADC(void) //模拟量转换为数字量并返回
{
unsigned char dat;
bit Ack;
IIC_Start();
IIC_SendByte(0x90);
Ack = IIC_WaitAck();
IIC_SendByte(0x03);
Ack = IIC_WaitAck();
IIC_Start();
IIC_SendByte(0x91);
Ack = IIC_WaitAck();
dat = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
return dat;
}
小结
这一篇完结以后,蓝桥杯单片机组历届省赛考点我们就差不多都练过了,就剩一个PWM还没练过,那么我也会在下一篇练习PWM。这样,拿个省一就差不多稳了,要考的模块都差不多复习好了,代码框架也就那样,基本没变过。
最后,如果我的代码和思路对你有帮助,别忘了点赞关注哦 >_< !