蓝桥杯嵌入式STM32G4 HAL库应用综述:省赛实践总结
文章目录
前言
由于去年大一的时候学了会单片机。参加了蓝桥杯单片机组,虽然只获得了一个省奖,但是带领我进入了单片机的世界,今年参加嵌入式组,由于之前一段时间去学CV去了,所以现在趁着这个机会复习一下stm32
硬件资源
嵌入式竞赛实训平台(CT117E-M4) 是北京国信长天科技有限公司设计、生产的一款“蓝桥杯全国软件与信息技术专业人才大赛-嵌入式设计与开发科目”专用竞赛平台,平台以STM32G431RBT6为主控芯片,预留扩展板接口,可为用户提供丰富的实验场景。
下载方式
由于板载了DAP Link,所以直接接入CN2(USB-Type)接口,并保证NRST、SWCLK、SWDIO的跳线连接,即可下载程序
CT117E-M4还板载了USB转串口功能默认与STM32G431RBT6的USART1连接。
模块总结
时钟树
选择24M外部高速晶振
LED灯
PC8-PC15:
PD2:
void LED_Disp(unsigned char Led)
{
//**将所有的灯熄灭
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8
|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
//根据ucLed的数值点亮相应的灯
//LD8-LD1对应Led的8个位
HAL_GPIO_WritePin(GPIOC, Led<<8, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}
键盘
unsigned char Key_Scan(void)
{
unsigned char unKey_Val = 0;
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET)unKey_Val = 1;
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET)unKey_Val = 2;
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET)unKey_Val = 3;
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)unKey_Val = 4;
return unKey_Val;
}
void Key_Proc(void)
{
//利用嘀嗒定时器消抖减速
if((uwTick - uwTick_Key)<100) return;
uwTick_Key = uwTick;
ucKey_Val = Key_Scan();
unKey_Down = ucKey_Val & (ucKey_Old ^ ucKey_Val);
ucKey_Up = ~ucKey_Val & (ucKey_Old ^ ucKey_Val);
ucKey_Old = ucKey_Val;
switch(unKey_Down)
{
case 1:
...
}
}
LCD
–
void LCD_Init(void);
void LCD_SetTextColor(vu16 Color);
void LCD_SetBackColor(vu16 Color);
void LCD_ClearLine(u8 Line);
void LCD_Clear(u16 Color);
void LCD_SetCursor(u8 Xpos, u16 Ypos);
void LCD_DrawChar(u8 Xpos, u16 Ypos, uc16 *c);
void LCD_DisplayChar(u8 Line, u16 Column, u8 Ascii);
void LCD_DisplayStringLine(u8 Line, u8 *ptr);
void LCD_SetDisplayWindow(u8 Xpos, u16 Ypos, u8 Height, u16 Width);
void LCD_WindowModeDisable(void);
void LCD_DrawLine(u8 Xpos, u16 Ypos, u16 Length, u8 Direction);
void LCD_DrawRect(u8 Xpos, u16 Ypos, u8 Height, u16 Width);
void LCD_DrawCircle(u8 Xpos, u16 Ypos, u16 Radius);
void LCD_DrawMonoPict(uc32 *Pict);
void LCD_WriteBMP(u32 BmpAddress);
void LCD_DrawBMP(u32 BmpAddress);
void LCD_DrawPicture(const u8* picture);
/*----- Medium layer function -----*/
void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue);
u16 LCD_ReadReg(u8 LCD_Reg);
void LCD_WriteRAM_Prepare(void);
void LCD_WriteRAM(u16 RGB_Code);
u16 LCD_ReadRAM(void);
void LCD_PowerOn(void);
void LCD_DisplayOn(void);
void LCD_DisplayOff(void);
/*----- Low layer function -----*/
void LCD_CtrlLinesConfig(void);
void LCD_BusIn(void);
void LCD_BusOut(void);
LCD_Init(); //常用的一些函数
LCD_Clear(White);
LCD_SetBackColor(White);
LCD_SetTextColor(Blue);
sprintf((char *)Lcd_Disp_String, " Hello world!!!");
LCD_DisplayStringLine(Line1, Lcd_Disp_String);
USART串口
由于板载了USB-串口,所以我们接上USB线就能用USART1
CubeMx配置
GPIO记得选择PA9 PA10
波特率可自行选择,和串口助手相同就行
开启中断
//发送
HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
//接受
HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
//常用格式
//串口中断开启
HAL_UART_Receive_IT(&huart1, &rx_buffer, 1);
//串口中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
LED(ON);
HAL_UART_Receive_IT(&huart1, &rx_buffer, 1);//这一句一定要加
}
//重定向c库函数printf
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
//重定向c库函数getchar,scanf
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
EEPROM
//EEPROM读写代码
void eeprom_write(unsigned char *pucBuf, unsigned char ucAddr, unsigned char Size)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(ucAddr);
I2CWaitAck();
while(Size--)
{
I2CSendByte(*pucBuf++);
I2CWaitAck();
}
I2CStop();
delay1(500);
}
void eeprom_read(unsigned char *pucBuf, unsigned char ucAddr, unsigned char Size)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(ucAddr);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
while(ucNum--)
{
*pucBuf++ = I2CReceiveByte();
if(Size)
I2CSendAck();
else
I2CSendNotAck();
}
I2CStop();
}
MCP4017可编程电阻
void resistor_write(uint8_t value)
{
I2CStart();
I2CSendByte(0x5E);
I2CWaitAck();
I2CSendByte(value);
I2CWaitAck();
I2CStop();
}
uint8_t resistor_read(void)
{
uint8_t value;
I2CStart();
I2CSendByte(0x5F);
I2CWaitAck();
value = I2CReceiveByte();
I2CSendNotAck();
I2CStop();
return value;
}
ADC
单ADC采集:
uint16_t getADC1(void)
{
uint16_t adc_value = 0;
HAL_ADC_Start(&hadc1);
adc_value = HAL_ADC_GetValue(&hadc1);
return adc_value;
}
多ADC采集:
//只需把hadc1改为hadc2
uint16_t getADC2(void)
{
uint16_t adc_value = 0;
HAL_ADC_Start(&hadc2);
adc_value = HAL_ADC_GetValue(&hadc2);
return adc;
}
DAC
void DAC_OUT(float Val)
{
uint32_t temp;
temp = (Val*4096/3.3f);
HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, temp);
}
测量PWM频率和占空比
原理:
1.选择通道一测量pwm的频率和占空比,上升沿触发
2.当上升沿来临时,②中寄存器会存下计数值,会触发中断,然后清零,这个值记做T
3.当下降沿来临时,③中寄存器会存下计数值,会触发中断,不会清零,这个值记做D
/* 启动定时器 */
HAL_TIM_Base_Start(&htim2);
/* 启动定时器通道输入捕获并开启中断 */
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_2);
//输入捕获中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM2)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
T_Count = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1)+1;
Freq = 1000000 / T_Count;
Duty = (float)D_Count/T_Count * 100;
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
D_Count = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2)+1;
}
}
}
定时器生成PWM波
PWM频率:
Fpwm =Tclk / ((arr+1)*(psc+1))(单位:Hz)
占空比:
duty circle = TIM15->CCR1 / arr(单位:%)
HAL_TIM_PWM_Start(&htim15,TIM_CHANNEL_1);
RTC时钟
//RTC相关变量
RTC_TimeTypeDef H_M_S_Time;
RTC_DateTypeDef Y_M_D_Date;
uint8_t Second;
//函数调用
HAL_RTC_GetTime(&hrtc, &H_M_S_Time, RTC_FORMAT_BIN);//读取日期和时间必须同时使用
HAL_RTC_GetDate(&hrtc, &Y_M_D_Date, RTC_FORMAT_BIN);
写在最后
离比赛时间不远了,接下来就是做几套真题,希望大家和我都能取得一个好成绩,加油加油加油
对了,总结几个我写程序平常容易出错的地方:
大家冲冲冲