【2023蓝桥杯 嵌入式组适用】CT117E-M4 新款开发板 3小时省赛模块 速成总结 纯分享,零套路,永久免费_哔哩哔哩_bilibili
上视频,有一定STM32基础的同学可以通过该视频快速了解,蓝桥杯嵌入式省赛各个模块的使用方法,小白不建议直接看。
下面是一些资料分享:
1、8~13界省赛代码
【蓝桥杯嵌入式】第十三届至第八届真题演示(附代码)_哔哩哔哩_bilibili
2、各界客观题资料
(有的客观题,学会查看官方给的手册其实更快一些,不过不用执着与客观题,看看就行,程序题才是大头)
#蓝桥杯嵌入式组#历年客观题解析_蓝桥杯嵌入式客观题_vircorns的博客-优快云博客
嵌入式蓝桥杯客观题总结(4.19)_蓝桥杯嵌入式客观题_little.jet的博客-优快云博客
【蓝桥杯嵌入式组】一、客观题(赛前必看) - 知乎 (zhihu.com)
3、省赛资源包
链接:https://pan.baidu.com/s/1T6nhFgYjTYOYtzJhofkgrw?pwd=nf0g
提取码:nf0g
4、各个模块的代码
(可以在观看完开头分享的学习视频后,当作代码速查速记资料)
----------------------------------------------------------------------------------------------------------------------
1、常用函数复习
stdio.h :
char text[30];
sprintf(text," PSD ");
sscanf(text,"%3s-%3s",code1,code2);
string.h :
strlen()
strcmp( , ) 两字符串相同返回0
memset( , , ) 内存赋值,memset(数组名,清零,数组长度)
stdlib.h :
atoi() 将字符串转换成整数型
stdbool.h :
bool
----------------------------------------------------------------------------------------------------------------------
2、.h文件框架
#ifndef _INTERRUPUT_H_
#define _INTERRUPUT_H_
#endif
----------------------------------------------------------------------------------------------------------------------
3、初始化设置(在main.c中)
led_disp(0x00); // 初始化,灯全灭
LCD_Init();
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
HAL_TIM_Base_Start_IT(&htim4); // 使能定时器,IT是指中断开启
HAL_TIM_PWM_Start(&htim16,TIM_CHANNEL_1); // pwm输出开启
HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);
HAL_UART_Receive_IT(&huart1,&rxdat1,1); // 串口开启
// 测量频率只需要打开一个通道。捕获上升沿,测一个周期的计数值。
// 测量占空比需要打开两个通道。直接通道捕获上升沿,测一个周期的计数值;间接通道捕获下降沿,测高电平的计数值。(CubMX上配置)
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);//频率测量捕获定时器开启 直接通道
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_2);//频率测量捕获定时器开启 间接通道
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2);
// 初始化频率,占空比
__HAL_TIM_SET_AUTORELOAD(&htim16, freq1);
__HAL_TIM_SET_AUTORELOAD(&htim17, freq2);
__HAL_TIM_SET_COMPARE(&htim16,TIM_CHANNEL_1,pwm1);
__HAL_TIM_SET_COMPARE(&htim17,TIM_CHANNEL_1,pwm2);
// __HAL_TIM_SET_AUTORELOAD() 是修改分频系数的,STM32CubeMX中的Counter Period不变,改变分频系数来改变频率。(例如 80MHZ,分频:800-1,Counter Period:100-1,现在是100HZ。要改成1000HZ,则freq1=80-1)
// __HAL_TIM_PRESCALER()好像也能用来修改频率,用法与上同
// 将定时器16通道1的比较值设为100 (pwm1),如果Counter Period为1000 (cubeMX中设置的),则占空比为10%
// While 1 中串口接收程序
While(1)
{
if(rx_pointer!=0)
{
int temp=rxdat1;
HAL_Delay(1);
if (temp==rxdat1)
uart_rx_proc();//完成接收
}
}
/*按键函数中只写标志位的改变,再转到while(1)中通过判断标志位来写灯、pwm频率占空比等的改变,因为按键函数中只有当按下才进去一次,后续功能可能执行不完整----可参考第十三届试题*/
// 串口发送
char temp[20];
sprintf(temp,"frq=%d\r\n",frq1);
HAL_UART_Transmit(&huart1,(uint8_t *)temp,strlen(temp),50);
// 串口接收-----第十二届试题
extern char rxdata[30];
extern uint8_t rxdat;
extern uchar rx_pointer;
char car_type[5];
char car_data[5];
char car_time[13];
void usart_rx(void)
{
if(rx_pointer>0)
{
if(rx_pointer==22)
{
sscanf(rxdata,"%4s:%4s:%12s",car_type,car_data,car_time);
}
else
{
char temp[20];
sprintf(temp,"Error\r\n");
HAL_UART_Transmit(&huart1,(uint8_t *)temp,strlen(temp),50);
}
rx_pointer=0; // 指针归位
memset(rxdata,0,30); // 清除数据,memset(数组名,清零,数组长度)
}
}
----------------------------------------------------------------------------------------------------------------------
4、LED配置
#include "led.h" --- 可写到interrupt中
void led_disp(uchar displed)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_All, GPIO_PIN_SET); // 熄灭所有灯
HAL_GPIO_WritePin(GPIOC, displed<<8, GPIO_PIN_RESET); // 点灯,左移8位
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}
/*
led_disp(0x01); // LED1亮
led_disp(0x02); // LED2亮
led_disp(0x04); // LED3亮,
// led_disp(0x03)二进制是011,是LED1和LED2亮,不是LED3亮
*/
----------------------------------------------------------------------------------------------------------------------
5、ADC采集
#include "myadc.h" --- 可写到interrupt中
double adc_read(ADC_HandleTypeDef *pin)
{
uint adc;
HAL_ADC_Start(pin);
adc = HAL_ADC_GetValue(pin);
return adc*3.3/4096; // ADC12位,2^12=4096
}
// 使用方法: adc_read(&hadc2)
--------------------------------------------------------------------------------------------------------------------
6、各种中断回调函数--按键、测PWM频率/占空比、串口通信等
#include "interrupt.h"
#include "usart.h" // 用串口时要包涵头文件!!!!!
#include "stdbool.h" // 使用 bool,要包含头文件
struct keys
{
uchar judge_flag;
bool key_state;
bool key_short; // 短按标志
bool key_long; // 长按标志
uint key_time; // 按键按下计时
};
struct keys key[4] = {0,0,0,0};
uint16_t led_5cnt=0;
uint16_t led_bling=0;
uchar led_5=0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) // cubemx中设置10ms/次
{
if(htim->Instance == TIM4) // 要在这个判断里面!!
{
if(++led_bling == 20) // 0.1秒闪烁,0.2秒一个周期
led_bling = 0;
if(++led_5cnt == 500) // 定时5秒
{
led_5 = 1;
led_5cnt = 0;
}
key[0].key_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);
key[1].key_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);
key[2].key_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2);
key[3].key_state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);
for(int i=0; i<4; i++)
{
switch (key[i].jugde_flag)
{
case 0:
{
if(key[i].key_state == 0)
{
key[i].jugde_flag = 1;
key[i].key_time = 0;
}
}break;
case 1:
{
if(key[i].key_state == 0) // 消抖
key[i].jugde_flag = 2;
else
key[i].jugde_flag = 0;
}break;
case 2:
{
if(key[i].key_state == 1) // 按键松开
{
if(key[i].key_time<70)
{
key[i].key_short=1;
}
key[i].judge_flag=0;
}
else
{
key[i].key_time++;
if(key[i].key_time>=70)
{
key[i].key_long=1;
}
}
}break;
}
}
}
}
/*----------------------------------------------------------------------------------------------------------------
函数中判断满足条件后(incorrect_ref==1),要先将led_5cnt,led_bling,led_5都清零,然后开始定时中断
例如while(1)中:
if(incorrect_ref==1) // LED2以0.1秒闪烁,闪烁5秒熄灭,incorrect_ref中断开启标志位
{
if(led_bling <=10)
{
LED_disp(0x02);
}
else if(led_bling >10)
{
LED_disp(0x00);
}
if(led_5==1)
{
incorrect_ref=0;
LED_disp(0x00);
led_5=0;
}
}
---------------------------实现时钟,该代码在中断回调函数中,参考第8界省赛题-------------------------
uint8_t time_hours=12;
uint8_t time_minute=59;
uint8_t time_seconds=50;
uint8_t time_tt=0;
if(++time_tt==100) // 定时器10ms一次,100次就是1s
{
time_tt=0;
if(++time_seconds==60)
{
time_seconds=0;
if(++time_minute==60)
{
time_minute=0;
if(++time_hours==13) // 12小时进制计数
{
time_hours=0;
}
}
}
}
------------------------------------------------------------------------------------------------------------*/
// -----测频率---占空比-----
uint time1_vaul = 0, time2_vaul = 0;
uint freq = 0;
float pulse = 0;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) // 回调函数
{
if(htim->Instance == TIM2)
{
time1_vaul = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
// 捕获计数器的值,一个周期
time2_vaul = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
// 捕获计数器的值,高电平
__HAL_TIM_SetCounter(htim, 0); // 计数值清零
freq = (80000000/80)/time1_vaul; // 时钟80MHZ,设置的80分频
pulse = time2_vaul/time1_vaul*100; // 占空比
HAL_TIM_IC_Start_IT(htim, TIM_CHANNEL_1); // 重新开启定时器
HAL_TIM_IC_Start_IT(htim, TIM_CHANNEL_2);
}
}
// 串口接收
char rxdata[30];
uint8_t rxdat1;
uchar rx_pointer;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_Receive_IT(&huart1,&rxdat1,1); // 要包含头文件#include "usart.h",不然报错
rxdata[rx_pointer++]=rxdat1;
}
-------------------------------------------------------------------------------------------------------------------
7、eeprom使用,在官方给的I2C文件中添加读写函数即可
#include "i2c - hal.h"
uchar eeprom_read(uchar addr)
{
uchar dat;
I2CStart();
I2CSendByte(0xa0); // 0xa0写,0xa1读;查看AT24C02芯片手册
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStop();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
dat=I2CReceiveByte();
I2CWaitAck();
I2CStop();
return dat;
}
void eeprom_write (uchar addr,uchar dat)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
2CSendByte(dat);
I2CWaitAck();
I2CStop();
}
--------------------------------------------------------------------
// 存储值到eeprom中,注意eeprom读写是8位的!!!
// 例:16位数据类型要拆分高8位,低8位。
uchar adc1, adc_h, adc_l;
adc1 = readADC(&hadc1);
adc_h = adc1 >> 8; // 高8位
adc_l = adc1 & 0xff; // 低8位
eeprom_write(1,adc_h);
eeprom_write(2,adc_l);
// 读取时也要注意是8位读取
adc1 = (eeprom_read(1)<<8) + eeprom_read(2); // 注意<<优先级低于+,要带括号!
---------------------------------------------------------------------
// 还有32位整形,浮点数的eeprom存取--始终记得eeprom是8位的!!!好像就考过难一点的就是浮点数的存储,可以先将浮点数扩大10或者100倍当作整形或者char型来处理。这么麻烦不要也罢,嗯,美名其曰懂得取舍!
// 32位整形数据读写
void wirte_32b(uint8_t add,uint32_t data)
{
eeprom_write(add,data&0xff);
HAL_Delay(2);
eeprom_write(add+1,(data>>8)&0xff);
HAL_Delay(2);
eeprom_write(add+2,(data>>16)&0xff);
HAL_Delay(2);
eeprom_write(add+3,(data>>24)&0xff);
HAL_Delay(2);
}
uint32_t read_32b(uint8_t add)
{
uint32_t temp;
temp=eeprom_read(add);
HAL_Delay(2);
temp+=eeprom_read(add+1)<<8;
HAL_Delay(2);
temp+=eeprom_read(add+2)<<16;
HAL_Delay(2);
temp+=eeprom_read(add+3)<<24;
HAL_Delay(2);
return temp;
}
// 浮点型数据读写
void write_flo(uint8_t add,float data)
{
uint32_t temp;
temp = (uint32_t)(data*100);
wirte_32b(add,temp);
}
float read_flo(uint8_t add)
{
uint32_t temp;
temp=read_32b(add);
return (float)temp/100;
}