十六届蓝桥杯嵌入式省赛直播基本外设驱动
前言
本文是准备2025年4月123日嵌入式蓝桥杯直播内容准备的一篇文章
1.创建工程
选择芯片
开启烧录引脚
开启高速时钟
主频设置成80回车
工程名称(不能有中文,包括路径)
考试的时候最下面哪一行取消勾选USE 然后选择这个文件夹打开
勾选几个
创建并且打开工程
编译无误后烧录器选择DAP
然后基本烧录无误
创建一个文件夹,专门用来存放自己的那个.c和.h文件
创建完成后添加路径
在DSP文件夹下创建基本的.c.h文件框架
在主函数中添加头文件
希望下载后直接运行,把reset run 勾选
2.LCD显示屏和LED等
1.LCD的基本配置
根据原理图
可以发现LCD和LED的引脚是共用的
考试的时候会给资源包,根据这个路径获取文件
需要三个文件
首先是把这两个.h复制到自己的文件
.c也放到里面
添加完后添加头文件编译
编写初始化代码驱动LCD显示屏
LCD_Init();
LCD_Clear(Black);
LCD_SetTextColor(White);
LCD_SetBackColor(Black);
char ss[20]="hello world!";
LCD_DisplayStringLine(Line0,(uint8_t *)ss);
成功亮起
接下来是LED
因为LCD和LED共用引脚
要处理他们互不干涉
2.处理LCD和LED互不干涉
PD2
锁存器要打开
处理这两个函数
IIC分别是写和读
分别对这两个函数的ODR输出寄存器记录状态
使用完恢复状态
这样修改后灯的状态就不会受到LCD显示屏的影响
烧录后灯不会乱两灭
3.LED的亮灭函数封装
根据原理图可以知道灯是PC8到PC15
void led_show(uint8_t number,uint8_t cmd)
{
static uint8_t led[8]={0};
switch (cmd)
{
case 0://假设给某个引脚低电平 亮
led[number-1]=1;break;
case 1://给高电平 灭
led[number-1]=0;break;
case 2://翻转某个引脚的电平
if(led[number-1])
led[number-1]=0;
else
led[number-1]=1;
}
for(uint8_t i=0;i<8;i++)
if(led[i])
HAL_GPIO_WritePin(GPIOC,1<<(8+i),0);
else
HAL_GPIO_WritePin(GPIOC,1<<(8+i),1);
HAL_GPIO_WritePin(GPIOD,1<<2,1);//打开锁存器
HAL_GPIO_WritePin(GPIOD,1<<2,0);//关闭锁存器
}
调用这个函数,第一个参数是第几个灯
第二个参数是对应的功能,0是亮
1是灭
2是翻转
2.非阻塞式按键
考试的题目,一般要求按下的时候,其他程序正常进行,所以要使用非阻塞
实现非阻塞的方法是定时器配合按键使用
因为一般的消抖时间为20ms,所以配置一个20msd的定时器中断
使能定时器
HAL_TIM_Base_Start_IT(&htim4);
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim==&htim4)
{
key_check();
}
}
void key_check()
{
static uint8_t flag[4]={0};
uint8_t numebr;
numebr=0;
switch (flag[numebr])
{
case 0:if(!HAL_GPIO_ReadPin(GPIOB,1<<numebr))
{
flag[numebr]=1;
}break;
case 1:if(HAL_GPIO_ReadPin(GPIOB,1<<numebr))
{
flag[numebr]=2;
}break;
case 2:
{
key1();
flag[numebr]=0;
}
}
numebr=1;
switch (flag[numebr])
{
case 0:if(!HAL_GPIO_ReadPin(GPIOB,1<<numebr))
{
flag[numebr]=1;
}break;
case 1:if(HAL_GPIO_ReadPin(GPIOB,1<<numebr))
{
flag[numebr]=2;
}break;
case 2:
{
key2();
flag[numebr]=0;
}
}
numebr=2;
switch (flag[numebr])
{
case 0:if(!HAL_GPIO_ReadPin(GPIOB,1<<numebr))
{
flag[numebr]=1;
}break;
case 1:if(HAL_GPIO_ReadPin(GPIOB,1<<numebr))
{
flag[numebr]=2;
}break;
case 2:
{
key3();
flag[numebr]=0;
}
}
numebr=3;
switch (flag[numebr])
{
case 0:if(!HAL_GPIO_ReadPin(GPIOA,1<<0))
{
flag[numebr]=1;
}break;
case 1:if(HAL_GPIO_ReadPin(GPIOA,1<<0))
{
flag[numebr]=2;
}break;
case 2:
{
key4();
flag[numebr]=0;
}
}
}
void key1()
{
led_show(1,2);
}
void key2()
{
led_show(2,2);
}
void key3()
{
led_show(3,2);
}
void key4()
{
led_show(4,2);
}
3.串口的不定时长接受以及接收后如何判断
先配置引脚,在打开串口,一把考试用的是9600
同时打开中断
串口重定向
把use micro打开
添加标准库头文件
int fputc(int ch,FILE* f)
{
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xffff);
return ch;
}
成功显示
不定时长代码
char buffer[1],OUT[100];
uint16_t length=0,time=0;
void uart_init()
{
HAL_UART_Receive_IT(&huart1,(uint8_t*)buffer,1);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart==&huart1)
{
OUT[length++]=buffer[0];
time=0;
HAL_UART_Receive_IT(&huart1,(uint8_t*)buffer,1);
}
}
void uart_chanle()
{
time++;
if((time>3)&&length)//超过40ms没有接受到字符并且已经接收到字符了
{
if(strcmp(OUT,"LED_ON")==0)
{
led_show(1,0);
}
if(strcmp(OUT,"LED_OFF")==0)
{
led_show(1,1);
}
memset(OUT,'\0',sizeof(OUT));//清空接收区
length=0;
time=0;
}
}
4.输入捕获获取频率
根据原理图可以知道引脚是PA15和PB4
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
__HAL_TIM_ENABLE_IT(&htim2,TIM_IT_UPDATE);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
__HAL_TIM_ENABLE_IT(&htim3,TIM_IT_UPDATE);
初始化函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim==&htim2)
{
//r40
uint16_t count1=TIM2->CCR1;
TIM2->CNT=0;
xl555_return(2,80000000/(80*count1));
}
if(htim==&htim3)
{
//r39
uint16_t count2=TIM3->CCR1;
TIM3->CNT=0;
xl555_return(3,80000000/(80*count2));
}
}
uint16_t xl555_return(uint8_t cmd,uint16_t count)
{
static uint16_t count1,count2;
switch (cmd)
{
case 0:
return count1;
case 1:
return count2;
case 2:count1 =count;break;
case 3:count2=count;break;
}
}
5.ADC
float adc_return(uint8_t number)
{
float adc;
switch (number)
{
case 0:
HAL_ADC_Start(&hadc1);
adc=(float)HAL_ADC_GetValue(&hadc1)/4096*3.3;
HAL_ADC_Stop(&hadc1);
return adc;
case 1:
HAL_ADC_Start(&hadc2);
adc=(float)HAL_ADC_GetValue(&hadc2)/4096*3.3;
HAL_ADC_Stop(&hadc2);
return adc;
}
}
5.IIC读写AT24C02
首先打开这个地址把这两个函数放到DSP文件夹
void eeprom_write(uint8_t address,uint8_t data)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CSendByte(data);
I2CWaitAck();
I2CStop();
HAL_Delay(500);
}
uint8_t eeprom_read(uint8_t address)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
uint8_t data=I2CReceiveByte();
I2CSendNotAck();
I2CStop();
return data;
}
在后面添加的代码
版本要用5的,要不然IIC会失败
记得加初始化,然后就驱动成功了