蓝桥杯嵌入式STM32G431RBT6模块配置详解及代码实践指南

1. 时钟配置

 80MHZ(按题目要求)

HSE

SYS debug->Serial Wire


2. LED灯

PD2所存设置low, 其余IO口上拉或高电平 

相关函数参考:

uint8_t led_sta;

// 显示当前lcd_sta状态
static void led_disp()      
{
    // 全灭
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);

    HAL_GPIO_WritePin(GPIOC,led_sta<<8,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}

// 点亮
void led_on(uint8_t sta)
{   
    led_sta |= sta;
    led_disp();
}

// 熄灭
void led_off(uint8_t sta)
{
    led_sta &= ~sta;
    led_disp();
}

3. LCD

GPIO设置output

赛题包有lcd的底层驱动

相关函数参考:

初始化

LCD_Init();

LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);

显示

char text_lcd[20];
sprintf(text_lcd,"          ");
LCD_DisplayStringLine(Line1, (uint8_t*)text_lcd);

4. 定时器

公式:

  • 频率:f = \frac{f_{system}}{(ARR+1)(PSC+1)))}
  • 周期:T = \frac{1}{f} = \frac{(ARR+1)(PSC+1)))}{f_{system}}
  • 占空比 = \frac{CCR}{ARR+1}
  •         duty = Pulse / (ARR+1)        Pulse = duty * (ARR+1)

     

    (数据手册P76) 

     4.1 按键

    GPIO上拉、定时器以10ms中断为例

    相关代码参考:

    按键定时器中断使能

    HAL_TIM_Base_Start_IT(&htim3);

    按键处理 

  • interrupt.h
  • #include "main.h"
    
    typedef struct{
        uint8_t shortprs;   // 短按
        uint8_t longprs;    // 长按
        uint8_t ispressed;  // 是否按下
        uint8_t procedures; // 流程
        uint8_t key_times;  // 按下时长
        uint8_t prs_keep;   // 保持按下状态
    }keys;  
  • interrupt.c:
  • #include "interrupt.h"
    
    keys key[4]={0,0,0,0};
    
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
        if(htim->Instance==TIM2)    // 10ms
        {
            key[0].ispressed = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
            key[1].ispressed = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
            key[2].ispressed = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
            key[3].ispressed = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
            
            for(int i = 0; i < 4; i++)
            {
                switch(key[i].procedures)
                {
                    case 0:
                    {
                        if(key[i].ispressed == 0)   key[i].procedures = 1;
                    }break;
                    
                    case 1:
                    {
                        if(key[i].ispressed == 0){
                            key[i].procedures = 2;
                            key[i].prs_keep = 1;
                        }
                        else    key[i].procedures = 0;
                    }break;
                    
                    case 2:
                    {
                        key[i].key_times++;
                        if(key[i].ispressed == 1)
                        {
                            if(key[i].key_times >= 70)  key[i].longprs = 1;
                            else    key[i].shortprs = 1;
                            key[i].procedures = 0;
                            key[i].key_times = 0;
                            key[i].prs_keep = 0;
                        }
                    }break;
                }
            }
        }
    }

    4.2 PWM输出

    例:PA6引脚输出100Hz,占空比可调节的脉冲信号

    公式:占空比=\frac{CRR}{ARR+1}

               Pulse=duty*(ARR+1)

    选择定时器(后面带CH的)

      

    PWM占空比cubeMX设置

     

    相关函数参考:

    pwm定时器使能

    HAL_TIM_PWM_Start(&htim16, TIM_CHANNEL_1);

    设置占空比 

    __HAL_TIM_SetCompare(&htim16, TIM_CHANNEL_1, pa6_duty);
    // TIM16->CCR1 = pa6_duty;    // 或者按照公式,直接改变CCR的值来改变占空比

    4.3 输入捕获测量PWM频率

    例:PA7引脚完成脉冲捕获功能,测量输入PA6的信号的频率

    公式:输入捕获频率 f = \frac{f_{sys}}{(PSC+1)*capture)}

    选择定时器 

    1.使能 2.选择通道模式 3.设置PSC

    相关代码参考:

    输入捕获定时器中断使能

    HAL_TIM_IC_Start_IT(&htim17, TIM_CHANNEL_1);

    interrupt.c:

    uint32_t frq, capture_val;
    void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
    {
        if(htim->Instance == TIM17)
        {
            // 捕获到上升沿,将CNT赋值给CCR
            // capture_val = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
            capture_val = TIM17->CCR1;
            TIM17->CNT = 0;    // 计数器清零
            frq = 80000000/(80*capture_val);
        }
    }

    4.4 输入捕获测555信号发生器频率

    配置PB4、PA15,选择定时器

                                                     

       

    相关代码参考:

    uint32_t frq_PB4, frq_PA15, capt_PB4, capt_PA15;
    
    void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
    {   
        // 捕获555信号发生器频率
        if(htim->Instance == TIM3)  // R39
        {
            capt_PB4 = TIM3->CCR1;
            TIM3->CNT = 0;
            frq_PB4 = 80000000/(80*capt_PB4);
        }
    
        if(htim->Instance == TIM8)  // R40
        {
            capt_PA15 = TIM8->CCR1;
            TIM8->CNT = 0;
            frq_PA15 = 80000000/(80*capt_PA15);
        }
    }

    5. ADC

    PB15、PB12设置ADCx_INxx

                            ​​​​​​​        ​​​​​​​        ​​​​​​​        

      

    相关代码参考: 

    double getADC(ADC_HandleTypeDef *pin)
    {
        unsigned int adc;
        HAL_ADC_Start(pin);     // 打开ADC
        adc = HAL_ADC_GetValue(pin);    // 读取
        return adc*3.3/4096;
    }

    6. EEPROM

    PB6和PB7选择GPIO_Output模式

    参赛数据包I2C驱动加读写函数

    i2c_hal.c

    void eeprom_write(uint8_t addr, uint8_t data)
    {
        I2CStart();
        I2CSendByte(0xa0);
        I2CWaitAck();
        I2CSendByte(addr);
        I2CWaitAck();
        I2CSendByte(data);
        I2CWaitAck();
        I2CStop();
        HAL_Delay(10);
    }
    
    uint8_t eeprom_read(uint8_t addr)
    {
        uint8_t data;
        I2CStart();
        I2CSendByte(0xa0);
        I2CWaitAck();
        I2CSendByte(addr);
        I2CWaitAck();
        I2CStop();
        
        I2CStart();
        I2CSendByte(0xa1);
        I2CWaitAck();
        data = I2CReceiveByte();
        I2CSendAck();
        I2CStop(); 
        return data;
    }

    7. USART

    一般题目波特率:9600(按照题目设置)

  • 基础的发送接收数据代码
  • 相关代码参考:

    usart.c:

    // 发送
    char trans_data[20];
    void UART_trans()
    {
        HAL_UART_Transmit(&huart1, (uint8_t*)trans_data, sizeof(trans_data), 50);
        HAL_Delay(1000);    
    }
    
    // 接收
    uint8_t rec_data;
    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    {
        if(huart->Instance == USART1)
        {
            HAL_UART_Receive_IT(huart, &rec_data, 1);
            // 接受一次之后返回给电脑(测试)HAL_UART_Transmit(&huart1, &rec_data, 1, 50);
        }
    }
  • 接收一串字符串
  • 第12届真题为例

             

    串口传输一个数据帧包含:起始位,数据位,结束位。(一共10bit)

    题目串口波特率9600s/bit

    传输一次需要 10*1/9600 = 0.00104s = 1.04ms

    解决方法:利用定时器(PSC=8000-1)cnt,如果cnt>15,也就是超过1.5ms则说明接受完成。

    代码:

    定时器4使能:

    HAL_TIM_Base_Start_IT(&htim4);

    接收函数:
     

    uint8_t rec_data;
    uint8_t rec_flg;
    char rec_buff[20], buff_cnt;
    
    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    {
        if(huart->Instance == USART1)
        {
            TIM4->CNT = 0;
            rec_flg = 1;
            rec_buff[buff_cnt++] = rec_data;
            HAL_UART_Receive_IT(huart, &rec_data, 1);
        }
    }
    
    void rec_string()
    {
        if(rec_flg)
        {
            if(TIM4->CNT > 15){  // 接收完成
                sscanf(rec_buff, "%4s:%4s:%12s", car_type, car_data, car_time);
            }
            else{
                char temp[20];
                sprintf(temp, "Error");
                HAL_UART_Transmit(&huart1, (uint8_t*)temp, strlen(temp), 50);
            }
            rec_flg = 0;
            memset(rec_buff,0,20);
            buff_cnt = 0;
        }
    
    }

    8. RTC实时时钟

    可以在cubeMX里设置年月日时分秒,以及闹钟时间和模式 

    设置和获取时间

    Format:    RTC_FORMAT_BIN

                    RTC_FORMAT_BCD

    HAL_RTC_SetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format);
    HAL_RTC_GetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format);
    HAL_RTC_SetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format);
    HAL_RTC_GetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format);

     闹钟中断处理函数

    void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
    {
    }

    /* 其他 */

  • 代码优化等级:0等级
  • 作者:WuOvo-_-

    物联沃分享整理
    物联沃-IOTWORD物联网 » 蓝桥杯嵌入式STM32G431RBT6模块配置详解及代码实践指南

    发表回复