1 学习STM32入门视频
向大家推荐一套宝藏级别的视频:
【STM32入门教程-2023版 细致讲解 中文字幕】
如果已经比过蓝桥杯单片机或学习过单片机相关课程的同学,你们可以尝试不需要STM32套件进行学习。如果没有学过单片机相关课程的同学,可以买套件边用边学。
尽量把这套视频看完,无论是对参加蓝桥杯嵌入式设计与开发竞赛(蓝桥杯)、嵌入式芯片与系统设计大赛STM32赛道(嵌入式大赛)或全国大学生物联网设计竞赛(华为杯)都有好处!
2 学习嵌入式开发板备赛视频
我主要看的是这套嵌入式视频:
【【备战2024蓝桥杯 嵌入式组】CT117E-M4 新款开发板 3小时省赛模块 速成总结】
从视频中可以学习到一些好的代码编写方式,从而避免各个外设的冲突、提高硬件运行效率。
3 备赛笔记
GPIO_Mode_AIN = 0x0, //模拟输入
GPIO_Mode_IN_FLOATING = 0x04, //浮空输入
GPIO_Mode_IPD = 0x28, //下拉输入
GPIO_Mode_IPU = 0x48, //上拉输入
GPIO_Mode_Out_OD = 0x14, //开漏输出
GPIO_Mode_Out_PP = 0x10, //推挽输出
GPIO_Mode_AF_OD = 0x1C, //复用开漏
GPIO_Mode_AF_PP = 0x18 //复用推挽
GPIO_SetBits //设置成高电平
GPIO_ResetBits //设置成低电平
HAL_GPIO_Write();//写GPIO电平状态函数
Key_State 里面的Key一定要初始化Key = 0;
长按键需要给25延时(Key_Time1)+长按键启用标志位
双击按键需要给40延时(Key_Time2)+双击按键启用标志位+暂时双击按键号
通用定时器可以产生4路频率相同,占空比不同的PWM输出
高级定时器可以产生7路频率相同,占空比不同的PWM输出
%d数据后面加空格 防止数据末位不清除
__HAL_TIM__SETCOMPARE(定时器,通道x, 占空比);
AT24C02 写一条语句延时5ms
MCP4017的从机地址(写操作):0X5E
随着我们向MCP中输入的数越大,他对应的电阻也就越大,当我们传入0x7f时,对应的电阻就是100K。这里要注意的一点是,我们写进去的一个数字(0-127),读出来也是一个数字,转化为电阻阻值:R = 787.4 * read_resistor 欧,电压:3.3*(R/(R+10)) (假设外接的电压为3.3)
新建工程
开启时钟(选择外部时钟) -> 配置时钟树 -> 配置DAP下载模式 -> 工程名 -> 配置MDK文件 -> 勾上生成code选项 -> 生成文件 -> 打开Keil -> 配置DAP下载 -> 勾上清除并更新 -> 建立bsp文件夹
LED
在CubeMX选择PC8-PC15、PD2为推挽输出模式 -> 配置PC8-PC15为高电平,PD2为低电平 -> 更新文件
->
void LED_Display(uchar data)
{
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_All, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, (~data)<<8, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}
(在main.c文件写代码时,写在Bagin和End注释之间)
LCD
复制资源包里LCD例程中2.h文件、1.c文件 -> 打开main.c,复制以下代码
LCD_Init();
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
LCD_DisplayStringLine(Line9, (unsigned char *)str);
-> 创建char str[30];、引用”stdio.h”使用sprintf函数
Key(短按键)
在CubeMX打开TI63时钟配置外部时钟源 -> 配置PSC、ARR -> 使能中断 -> 更新文件
->
uint8_t Key_State(void)
{
uchar Key = 0;
if(!HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0))
Key = 1;
if(!HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1))
Key = 2;
if(!HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2))
Key = 3;
if(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0))
Key = 4;
return Key;
}
void Key_Loop(void)
{
static uint8_t LastState, NowState;
uint8_t i;
LastState = NowState;
NowState = Key_State();
for(i = 1;i <= 4;i ++)
{
if(LastState == 0 && NowState == i)
KeyNum = i;
}
}
->
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//中断回调函数(中断服务函数)
{
static uint8_t Count0;
if(htim -> Instance == TIM6)
{
if(++Count0 >= 20)
{
Count0 = 0;
KeyStart = 1;
}
}
}
->
HAL_TIM_Base_Start_IT(&htim6);//使能定时器中断
Key(长按键)
uint8_t Key_Short, Key_Long, Key_Time, Long_State = 1;
void Key_Loop(void)
{
static uint8_t LastState, NowState;
uint8_t i;
LastState = NowState;
NowState = Key_State();
for(i = 1;i <= 4;i ++)
{
if(LastState == 0 && NowState == i)
Key_Time = 0;
if(LastState == i && NowState == i)
{
if(++Key_Time >= 25 && Long_State)
{
Key_Long = i;
Long_State = 0;
}
}
if(LastState == i && NowState == 0)
{
if(Key_Time < 25)
Key_Short = i;
Long_State = 1;
}
}
}
PWM
在CubeMX打开相应定时器选择PWM生成选项 -> 配置时钟PSC:待定频率,ARR:100-1、CCR:占空比初值 -> 更新文件
->
HAL_TIM_PWM_Start(&htim16, TIM_CHANNEL_1);//使能PWM某通道输出
->
__HAL_TIM_SetCompare(&htim16, TIM_CHANNEL_1, PA6_PWM);//改变占空比
IC(测频率+占空比):
在CubeMX打开相应定时器 - > 配置Clock Source -> 选择CH1为直接通道、CH2为间接通道 -> 配置时钟PSC:80-1、ARR满重装值 -> CH1为上升沿触发、CH2为下降沿触发 -> 配置从模式(Combined Reset Trigger Mode) -> 选择触发源(TI1FP1)-> 更新文件 -> 创建IC.c、IC.h文件 -> 引入tim.h头文件 ->
uint32_t Read_Fre(uint8_t Command)
{
if(Command == 15) return 1000000 / (HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1) + 1);
else if(Command == 4) return 1000000 / (HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_1) + 1);
else return 0;
}
double Read_Buty(uint8_t Command)
{
if(Command == 15) return (HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_2) + 1) * 100.0 / (HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1) + 1);
else if(Command == 4) return (HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_2) + 1) * 100.0 / (HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_1) + 1);
else return 0;
}
->
HAL_TIM_IC_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_IC_Start(&htim3, TIM_CHANNEL_1);//使能通道1
HAL_TIM_IC_Start(&htim2, TIM_CHANNEL_2);
HAL_TIM_IC_Start(&htim3, TIM_CHANNEL_2);//使能通道2
IC(中断测频率)
在CubeMX打开相应定时器TIMx的时钟 -> 选择相应通道CHx -> 配置时钟PSC:80-1、ARR满重装值-> 使能中断 -> 更新文件 -> 创建IC.c、IC.h文件 ->
uint32_t TIM2_IC_CRR1;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim -> Instance == TIM2)
{
TIM2_IC_CRR1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
__HAL_TIM_SetCounter(htim, 0);
}
}
uint32_t Read_Fre(void)
{
return 1000000 / (TIM2_IC_CRR1 + 1);
}
->
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);//使能输入捕获中断
ADC + DMA
在CubeMX打开相应引脚ADC通道 -> 配置ADC1、ADC2中相应通道使能(Single-ended) -> 使能连续转换 -> 添加DAM -> 配置循环模式Circular -> 使能DMA请求为连续模式 -> 失能DMA中断 -> 更新文件 ->
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)adc1,1);
HAL_ADC_Start_DMA(&hadc2,(uint32_t *)adc2,1); //使能DAM转运
IIC
在CubeMX设置PB6、PB7引脚为输出模式 ->
void Write_AT24C02(uint8_t Command, uint8_t Data)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(Command);
I2CWaitAck();
I2CSendByte(Data);
I2CWaitAck();
I2CStop();
}
uint8_t Read_AT24C02(uint8_t Command)
{
uint8_t Data;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(Command);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa0 | 0x01);
I2CWaitAck();
Data = I2CReceiveByte();
I2CSendNotAck();//不需要继续读就给非应答
I2CStop();
return Data;
}
uint8_t Read_AT24C02(uint8_t Command)
{
uint8_t Data;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(Command);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa0 | 0x01);
I2CWaitAck();
Data = I2CReceiveByte();
I2CSendNotAck();//不需要继续读就给非应答
I2CStop();
return Data;
}
USART1
在CubeMX配置USART1模式为Asynchronous -> 配置波特率 -> 使能中断 -> 配置PA9、PA10为USART1 -> 更新文件 -> 创建MyUSART.c、.h文件 -> 引用usart.h->
uint8_t Rxdata,Receive_Over, pRxPacket;
char RxPacket[30];
void Send_USART(char *data)
{
HAL_UART_Transmit(&huart1, (uint8_t *)data, strlen(data), 50);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart -> Instance == USART1)
{
HAL_UART_Receive_IT(huart, &Rxdata, 1);
RxPacket[pRxPacket ++] = RXdata;
}
}
void Receive_USART(void)
{
static uint8_t p;
if(pRxPacket != 0)
{
p = pRxPacket;
HAL_Delay(1);
if(p == pRxPacket)
{
Receive_Over =1;
Send_USART(RxPacket);
pRxPacket = 0;
memset(RxPacket, 0, 30);
}
}
}
->
HAL_UART_Receive_IT(&huart1, &Rxdata, 1);//使能接收中断
4 备赛过程
嵌入式省赛备赛过程与单片机备赛过程类似,这里不再赘述,详情可以查看博主的另一篇博客:
【蓝桥杯单片机大一零基础到国二经验分享】
奇数届嵌入式国赛备赛时,可以多学习一些串口方面的c语言函数,比如第十五届嵌入式串口相关的收发数据及提取数据就比较多。
偶数届嵌入式国赛备赛时,需要学习扩展板相关外设的使用。
5 资料
如需十五届嵌入式资料可以私信我,本人很乐意开源,欢迎大家在评论区交流学习,预祝大家在蓝桥杯嵌入式设计与开发竞赛中取得优异成绩!!!