当前位置: 首页 > article >正文

【蓝桥杯单片机】第十一届省赛

一、真题

 

二、创建工程

1.在C盘以外的盘新建文件夹,并在文件夹里面创建两个文件夹Driver 和Project

2.打开keil软件,在新建工程并选择刚刚建好的project文件夹,以准考证号命名

 3.选择对应的芯片型号

 4.选择否,即不创建启动文件

5.勾上生成hex文件的功能

 

6.添加头文件路径

三、模块构建 

1.编写初始化函数(init.c) 

void Cls_Peripheral(void);

  1. 关闭led    led对应的锁存器由Y4C控制
  2. 关闭蜂鸣器和继电器 由Y5C控制

2.编写LED函数(led.c)

void Led_Disp(unsigned char ucLed);

  1. 将ucLed取反的值赋给P0

  2. 开启锁存器 y4

  3. 关闭锁存器 y4

3.编写数码管函数(seg.c)

void Seg_Tran(unsigned char *pucSeg_Buf,unsigned char *pucSeg_Code);

(1)段码转换函数

  • 定义两个变量i,j
  • for循环加Switch语句进行段码转换,在资源数据包查找段码表,并根据题目要求进行段码转换
  • 注意添加空格代表都不显示
  • 注意8+4是C 不是A

void Seg_Disp(unsigned char *pucSeg_Code,unsigned char ucSeg_Pos);

(2)数码管显示函数

  • 要对数码管进行消隐y7
  • 显示的位置 y6
  • 显示的内容y7

4. 编写矩阵键盘代码(key.c)

unsigned char Key_Read_KBD(void);

  1. 有返回值
  2. 16个按键,要用十六位数据类型 unsigned int
  3. 依次将每一列设置为低电平,读取P3的低四位(&0x0f)存储到变量Key_New里,要忘记每个都左移4位,然后记得|
  4. 用Switch语句将按键按下后的值进行判断(Key_New取反 便于理解)
  5. 返回对应按键的值
  6. 不要忘记default 返回都没有按下的值 设为0

5.编写ADC代码

unsigned char PCF8591_ADC(void);

  1.  定义SCL,SDA
  2. 返回值类型
  3. 添加"intrins.h"头文件,接触nop错误
  4. 定义变量用于存储采集的电压
  5. 写入流程:开始--发送写入地址--等待应答--发送电位器地址--等待应答
  6. 读取流程:开始--发送读取地址--等待应答--变量接收数据--发送应答1--终止
  7. 读取地址为0x91 写入地址为0x90
  8. 电位器地址为0x43 
  9. 不要忘记把temp返回

 6.编写AT24C02代码

void EEPROM_Read(unsigned char *pucBuf,unsigned char addr,unsigned char num);

  •  读取流程:开始--发送写入地址--等待应答--发送写入位置-等待应答--开始--发送读取地址--等待应答--while(num--)来逐个存储读取的数据--if判断num是否为0--终止

void EEPROM_Write(unsigned char *pucBuf,unsigned char addr,unsigned char num)

  • 开始--发送写入地址--等待应答--发送写入位置--等待应答-- while(num--)来逐个将数据写入(加入延时保证稳定性)--终止

7.定时器函数编写

void Timer0Init(void); 

  1. 在sti-isp软件中生成定时长度为1ms的c代码,直接复制
  2. 不要忘记打开定时器0的开关和定时器总开关

 四、主函数代码

1.添加好所有头文件在主函数和工程文件夹中

2.外设初始化,定时器初始化,打开中断总开关

3.数码管函数编写

  • 定义数组和变量,数组分别为12为和8位,不加*  变量赋初值为0
  • 编写Seg_Proc();函数
  • 添加时间变量在定时器0中断进行自加
  • 200ms
  • 动态显示添加到中断里
  • 判断模式
  • 数码管转换函数不要忘

4.ADC函数编写

  • 时间200
  • 将读取的值赋值给变量,实际的值需要除以51.0是真实电压值

5.按键函数编写

  • 不用NE555时,不要短接,否则按键会失效

6.led函数编写

  •  200ms
  • 最后不要忘记调用led显示函数

五、难点解析

1.关于EEPROM 的断电保存

2.触发条件

3.指示灯 用到了ulms

4.无效按键的触发 

六、主函数代码

#include <stdio.h>
#include "seg.h"
#include "led.h"
#include "init.h"
#include "key.h"
#include "iic.h"
#include "tim.h"
//Seg
unsigned char pucSeg_Buf[12],pucSeg_Code[8],ucSeg_Pos=0;
//ADC
unsigned char ucADC=0;
float ADC_Pram=0;
unsigned int uicount=0;
unsigned char ucADC_Old=0;
//led
unsigned char ucLed=0;
//key
unsigned char Key_Val=0,Key_Val_Old=0;
unsigned int uiError=0;
//EEPROM
unsigned char EEPROM_Buf[2];
//timer
unsigned long ulms=0;
unsigned long ulled=0;
unsigned int uiSeg_Dly=0;
unsigned int uiADC_Dly=0;
unsigned int uiKey_Dly=0;
unsigned int uiLed_Dly=0;

//function
void Seg_Proc(void);
void ADC_Proc(void);
void Key_Proc(void);
void Led_Proc(void);
 
//mode
unsigned char Disp_Mode=0;

void main(void)
{
	Cls_Peripheral();
	EEPROM_Read(EEPROM_Buf,0x00,1);
	ADC_Pram=EEPROM_Buf[0]/10.0;
	Timer0Init();
	EA=1;
	while(1)
	{
		Seg_Proc();
		ADC_Proc();
		Key_Proc();
		Led_Proc();
	}
}
void Led_Proc(void)
{
	if(uiLed_Dly<200)
	return;
	uiLed_Dly=0;
	
	if(((ucADC/51.0)<ADC_Pram)&&(ulms-ulled>5000))
	{
		ucLed|=0x01;
	}
	else
		
	{
	  ucLed&=~0x01;
	}
	if(uicount%2==0)
	{
		ucLed&=~0x02;
	}
	else
	{
	  ucLed|=0x02;
	}
	if(uiError>=3)
	{
		ucLed|=0x04;
	}
	else
	{
	  ucLed&=~0x04;
	}
	Led_Disp(ucLed);
}

void Seg_Proc(void)
{
	if(uiSeg_Dly<200)
	return;
	uiSeg_Dly=0;
	if(Disp_Mode==0)
	{
		sprintf(pucSeg_Buf,"U    %4.2f",ucADC/51.0);
	}
	else if(Disp_Mode==1)
	{
		sprintf(pucSeg_Buf,"P    %4.2f",ADC_Pram);
	}
	else
	{
		sprintf(pucSeg_Buf,"N%7u",uicount);
	}
	Seg_Tran(pucSeg_Buf,pucSeg_Code);
}
void ADC_Proc(void)
{
	if(uiADC_Dly<500)
	return;
	uiADC_Dly=0;
	ucADC=PCF8591_ADC();
	if(((ucADC_Old/51.0)>ADC_Pram)&&((ucADC/51.0)<=ADC_Pram))
	{
		uicount++;
		ulled=ulms;
	}
	if(((ucADC_Old/51.0)<ADC_Pram)&&((ucADC/51.0)>=ADC_Pram))
	{
		ulled=ulms;
	}
	ucADC_Old=ucADC;
}
void Key_Proc(void)
{
	if(uiKey_Dly<20)
	return;
	uiKey_Dly=0;
	
	Key_Val=Key_Read_KBD();
	if(Key_Val==Key_Val_Old)
		return;
	switch (Key_Val)
	{
		case 12:
			uiError=0;
			Disp_Mode=(Disp_Mode+1)%3;
		if(Disp_Mode==2)
		{
			EEPROM_Buf[0]=(unsigned char)(ADC_Pram*10);
			EEPROM_Write(EEPROM_Buf,0x00,1);
		}
			break;
		case 13:
			if(Disp_Mode==2)
			{
				uiError=0;
				uicount=0;
			}
			else
			{
				uiError++;
			}
		case 16:
			if(Disp_Mode==1)
			{
				uiError=0;
				if(ADC_Pram>=5)
				{
					ADC_Pram=0;
				}
				else
				{
				ADC_Pram+=0.5;
				}
			}
			else
			{
				uiError++;
			}
			break;
			case 17:
			if(Disp_Mode==1)
			{
				uiError=0;
				if(ADC_Pram<=0.0)
				{
					ADC_Pram=5.0;
				}
				else
				{
				ADC_Pram-=0.5;
				}
			}
			else
			{
				uiError++;
			}
			break;
	}
		Key_Val_Old=Key_Val;
}
void Time_0(void) interrupt 1
{
	ulms++;
	uiSeg_Dly++;
	uiADC_Dly++;
	uiKey_Dly++;
	uiLed_Dly++;
	if(ulms%2==0)
	{
		ucSeg_Pos=(ucSeg_Pos+1)%8;
		Seg_Disp(pucSeg_Code,ucSeg_Pos);
	}
}


http://www.kler.cn/a/582508.html

相关文章:

  • MATLAB 控制系统设计与仿真 - 24
  • KVM制作Ubuntu 22.04.5系统qcow2类型镜像
  • 下一代AIGC一站式商业解决方案Chat Nio
  • 【反无人机目标检测】DRBD-YOLOv8
  • react实现一个列表的拖拽排序(react实现拖拽)
  • 简单易懂Modbus Tcp和Rtu的异同点
  • 神经网络完成训练的详细过程
  • AI日报 - 2025年3月13日
  • 蓝桥真题讲解
  • Android 列表页面终极封装:SmartRefreshLayout + BRVAH 实现下拉刷新和加载更多
  • 无广告记账助手:个人小企业财务管理
  • 02.Kubernetes 集群部署
  • UE5.4分层渲染设置
  • 神经网络机器学习中说的过拟合是什么意思
  • Spring Boot + InfluxDB 实现高效数据存储与查询
  • 【实战-解决方案】Webpack 打包后很多js方法报错:not defined
  • 关于MCP SSE 服务器的工作原理
  • Kotlin D3
  • Vite项目中vite.config.js中为什么只能使用process.env,无法使用import.meta.env?
  • 使用expect工具实现远程批量修改服务器密码