第六屆 藍橋杯 嵌入式 省賽

參考

第六屆藍橋杯嵌入式省賽程序設計題解析(基于HAL庫)_藍橋杯嵌入式第六屆真題-CSDN博客

一、分析功能

RTC 定時

1)時間初始化

2)定時上報電壓時間

ADC測量

采集電位器的輸出電壓信號。

串行功能

1)傳送要設置的k值

2)傳送上報的電壓

3)保存 E2PROM

LED指示燈

電壓大于閾值時,閃爍。

LCD顯示

1)電位器輸出電壓

2)k 值

3)LED閃爍開關狀態

4)系統時間

按鍵

1)開關LED閃爍

2)設置上報時間

3)切換時、分、秒

4)調整時間

整體邏輯圖

二、CubeMX 配置

1.基礎配置

新建一個工程,選擇芯片?STM32G431RBT6

?配置系統 SYS

修改中斷優先級

配置時鐘RCC

時鐘樹設置:?

輸入頻率其實就是晶振提供的24MHz,采用HSE(高速外部時鐘源)。至于SYSCLK 系統時鐘的80MHz 可以通過 PLLM、PLL配置出來。

2. KEY+LED

?

設置電氣屬性

將 PC8-PC15 以及 PD2 設置為輸出;

將 PB0,PB1,PB2,PA0 設置為 輸入。

設置 LED 的初始狀態

由于LED低有效,故設置LED的輸出設置成High-----這樣上電的時候燈是熄滅的

3. UART

設置MODE為異步通信(Asynchronous)
修改波特率9600(根據題目修改)
NVIC Settings一欄使能接受中斷

4. ADC

5. TIM

使能定時器6(基本定時器)?

配置定時器2(輸入捕獲)

PA15選擇定時器2的通道1

?

配置定時器3(輸出PWM)

選擇80分頻,一兆的頻率進行1000計數,頻率就是1000HZ,使能自動重裝載。

TIM3的占空比設置成30%,則脈沖就設置成300?

TIM17的占空比設置成60%,則脈沖設置成600

配置定時器15(輸出方波---是比較輸出模式)

6. RTC

RTC時鐘頻率 = RTC時鐘源 / ((Asynchronous Predivider value + 1) * (Synchronous Predivider value + 1))

7. 生成代碼

三、編寫代碼

mcu 開發的架構層次:

由于藍橋杯是沒有 RTOS 的,且BSP和HAL都是現成的。只要開發應用層和修改MCU即可即可。

接下來是對應用層的開發。

1. 頭文件

mcu編程和系統編程的代碼風格有點不一樣。mcu貌似把頭文件全放main.c上了,而系統編程都是放在 *.h 中。可能mcu的代碼量不夠多,沒必要這么寫。

Cube設定好后,會有這些應用層的文件:

也就是 ADC、RTC、UART、TIM。

LED和KEY是不用再另起一個文件寫,但是為了書寫規范,還是打算寫一個key_led.c。

而LCD是需要從賽點資源庫導入進來的。

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "rtc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "lcd.h"
#include "i2c_hal.h"

2. 函數聲明和主函數

函數申明

void Key_Proc(void);
void Led_Proc(void);
void Lcd_Proc(void);
void Usart_Proc(void);

主函數

int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_ADC1_Init();MX_ADC2_Init();MX_TIM2_Init();MX_TIM6_Init();MX_USART1_UART_Init();MX_RTC_Init();MX_TIM3_Init();MX_TIM15_Init();MX_TIM17_Init();/* USER CODE BEGIN 2 */LCD_Init();LCD_Clear(White);LCD_SetBackColor(White);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */Key_Proc();Led_Proc();Lcd_Proc();Usart_Proc();/* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

3. 函數定義

3.1 按鍵、LCD

我們重新審題:

B1:LED燈的打開和關閉

B2:LCD 的切換

B3:切換時分秒

B4:修改時分秒

時間窗口
//*減速變量
//方式1
__IO uint32_t uwTick_Key_Set_Point = 0;//控制Key_Proc的執行速度if((uwTick -  uwTick_Key_Set_Point)<50)	return;//減速函數uwTick_Key_Set_Point = uwTick;//方式2
uint32_t uskey;//stm32g4xx_it.c
/* USER CODE BEGIN PV */
extern uint32_t uskey;
/* USER CODE END PV */
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
/* USER CODE BEGIN SysTick_IRQn 1 */
uskey++;//實現usled每隔1ms自增1
/* USER CODE END SysTick_IRQn 1 */
}

兩種寫法,挑一個。

按鍵模版
//*按鍵掃描專用變量
uint8_t ucKey_Val, unKey_Down, ucKey_Up, ucKey_Old;ucKey_Val = Key_Scan();
unKey_Down = ucKey_Val & (ucKey_Old ^ ucKey_Val); 
ucKey_Up = ~ucKey_Val & (ucKey_Old ^ ucKey_Val);	
ucKey_Old = ucKey_Val;

典型的3行按鍵模版,背就完了。

uint8_t Key_Scan(void);uint8_t Key_Scan(void)
{uint8_t key_val=0;if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==GPIO_PIN_RESET){key_val=1;}if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==GPIO_PIN_RESET){key_val=2;}if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)==GPIO_PIN_RESET){key_val=3;}if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_RESET){key_val=4;}return key_val;
}
B1按鍵功能實現
void Key_Proc(void)
{if((uwTick -  uwTick_Key_Set_Point)<50)	return;//減速函數uwTick_Key_Set_Point = 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;//B1完成LED報警功能的打開和關閉if(unKey_Down == 1){LED_Ctrl ^= 0x01;//讓最后一位翻滾}
}

對LED異或1是切換狀態的基本操作。

LCD顯示

LCD的切換,就是清屏后,再刷上去。

LCD 的兩個界面:

界面1

1、電位器輸出電壓

2、k值

3、LED的狀態

4、系統時間

界面2

1、Setting?

2、XX-XX-XX

延時后,讀取電壓和RTC,而電壓與RTC的實現后面會實現。?

__IO uint32_t uwTick_Lcd_Set_Point = 0;//控制Lcd_Proc的執行速度
float R37_Voltage;
RTC_TimeTypeDef H_M_S_Time;
RTC_DateTypeDef Y_M_D_Date;void Lcd_Proc(void)
{if((uwTick -  uwTick_Lcd_Set_Point)<100)	return;//減速函數uwTick_Lcd_Set_Point = uwTick;//數據采集區R37_Voltage = ((((float)getADC2())/4096)*3.3);HAL_RTC_GetTime(&hrtc, &H_M_S_Time, RTC_FORMAT_BIN);//讀取日期和時間必須同時使用HAL_RTC_GetDate(&hrtc, &Y_M_D_Date, RTC_FORMAT_BIN);}

?那么我們要設置兩個page

page0:數據顯示區
uint8_t Interface_Num;//0x00-顯示界面,0x10-設置上報時間的小時,0x11-設置分鐘,0x12-設置秒。
uint8_t Lcd_Disp_String[21];//最多顯示20個字符
uint8_t k_int = 1;void Lcd_Proc(void)
{......if(Interface_Num == 0x00)	//page0{sprintf((char *)Lcd_Disp_String, " V1:%4.2fV", R37_Voltage);LCD_DisplayStringLine(Line2, Lcd_Disp_String);sprintf((char *)Lcd_Disp_String, " k:%3.1f", (k_int*0.1));LCD_DisplayStringLine(Line4, Lcd_Disp_String);if(LED_Ctrl == 0)sprintf((char *)Lcd_Disp_String, "     LED:ON");elsesprintf((char *)Lcd_Disp_String, "     LED:OFF");LCD_DisplayStringLine(Line6, Lcd_Disp_String);sprintf((char *)Lcd_Disp_String, "     T:%02d-%02d-%02d", (unsigned int)H_M_S_Time.Minutes, (unsigned int)H_M_S_Time.Second;LCD_DisplayStringLine(Line8, Lcd_Disp_String);}
}

UART傳輸的數據,后面會實現。

page1:時間設置區

設置的 Interface_Num 為 0x10,以及右移4位,能夠兼顧 0x10,0x11,0x12 三個狀態保持在同Page 中。

__IO uint32_t uwTick_SETTING_TIME_Set_Point = 0;//控制待設置的時間數值閃爍
uint8_t SETTING_TIME_Ctrl = 0;// 0-亮,1-滅,控制時間設置界面的待設置值的閃爍功能void Lcd_Proc(void)
{......//時間設置區if((Interface_Num>>4) == 0x1)	//進入設置界面{sprintf((char *)Lcd_Disp_String, "     Setting");LCD_DisplayStringLine(Line2, Lcd_Disp_String);sprintf((char *)Lcd_Disp_String, "     T:%02d-%02d-%02d", (unsigned int)Clock_Comp_Disp[0], (unsigned int)Clock_Comp_Disp[1], (unsigned int)Clock_Comp_Disp[2]);if((uwTick - uwTick_SETTING_TIME_Set_Point)>=500){uwTick_SETTING_TIME_Set_Point = uwTick;SETTING_TIME_Ctrl ^= 0x1;}if(SETTING_TIME_Ctrl == 0x1)	//控制閃爍,時間設置的時候閃爍{if(Interface_Num == 0x10)	//設置時{Lcd_Disp_String[6] = ' ';Lcd_Disp_String[7] = ' ';}else if(Interface_Num == 0x11)	//設置分{Lcd_Disp_String[9] = ' ';Lcd_Disp_String[10] = ' ';}else if(Interface_Num == 0x12)	//設置秒{Lcd_Disp_String[12] = ' ';Lcd_Disp_String[13] = ' ';}}LCD_DisplayStringLine(Line5, Lcd_Disp_String);}
}

RTC的時間后面會實現。

B2按鍵功能實現
uint8_t Clock_Comp_Disp[3] = {0,0,0};//鬧鐘比較值的初值(顯示專用)
uint8_t Clock_Comp_Ctrl[3] = {0,0,0};//鬧鐘比較值的初值(控制專用)void Key_Proc(void)
{......	//B2完成兩個界面的切換if(unKey_Down == 2){if(Interface_Num == 0x00)	//數據顯示區{LCD_Clear(White);	//清屏Interface_Num = 0x10;}else if((Interface_Num>>4) == 0x1){LCD_Clear(White);	//清屏Interface_Num = 0x00;Clock_Comp_Ctrl[0] = Clock_Comp_Disp[0];	//更新鬧鐘顯示值到控制值Clock_Comp_Ctrl[1] = Clock_Comp_Disp[1];	//更新鬧鐘顯示值到控制值	Clock_Comp_Ctrl[2] = Clock_Comp_Disp[2];	//更新鬧鐘顯示值到控制值	}}
}

B3按鍵功能實現
void Key_Proc(void)
{...//B3切換時分秒,切換時會閃爍if(unKey_Down == 3){if((Interface_Num>>4) == 0x1)//時分秒循環切換if(++Interface_Num == 0x13)Interface_Num = 0x10;}
}

B4功能實現

時間設定,具體是在 LCD 部分實現。按鍵只實現時間重置而已。

設置的 Interface_Num 為 0x10,以及右移4位,能夠兼顧 0x10,0x11,0x12 三個狀態保持在同Page 中。

void Key_Proc(void)
{......//B4調整時間,其實按鍵這塊只是實現時間到底后回到0if(unKey_Down == 4){if(Interface_Num == 0x10){if( ++Clock_Comp_Disp[0] ==24)Clock_Comp_Disp[0] = 0;}if(Interface_Num == 0x11){if( ++Clock_Comp_Disp[1] ==60)Clock_Comp_Disp[1] = 0;}if(Interface_Num == 0x12){if( ++Clock_Comp_Disp[2] ==60)Clock_Comp_Disp[2] = 0;}}
}

3.2?LED

重新審題

V 1 >V DD *k 時,指示燈LD1 0.2 秒為間隔閃爍,閃爍功能可以通過按鍵關閉。
__IO uint32_t uwTick_Led_Set_Point = 0;//控制Led_Proc的執行速度
uint8_t ucLed;
__IO uint32_t uwTick_LED_bulingbuling_Set_Point = 0;//控制LED報警閃爍的打點變量void Led_Proc(void){if((uwTick -  uwTick_Led_Set_Point)<50)	return;//減速函數uwTick_Led_Set_Point = uwTick;if(LED_Ctrl == 0x1)//關閉LED的功能的時候ucLed = 0x00;else//開啟LED功能的時候{if(R37_Voltage>=(3.3*k_int*0.1)){//200ms 閃爍if((uwTick-uwTick_LED_bulingbuling_Set_Point)>=200){uwTick_LED_bulingbuling_Set_Point = uwTick;ucLed ^= 0x1;}}elseucLed = 0x00;}LED_Disp(ucLed);
}
void LED_Disp(uint8_t ucLed);
void LED_Disp(uint8_t ucLed)
{//**將所有的燈熄滅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的數值點亮相應的燈HAL_GPIO_WritePin(GPIOC, ucLed<<8, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);	
}

3.3?串口

重新審題

定時上報電壓V1

格式:V1電壓值】+k 值】+【時間】【命令結束標志】

“2.21+0.1+123030\n”
12 30 30 秒上報電壓值為 2.21V k 值為 0.1
串口接收數據
當第一個字符收到 k,則開始緩存。
uint8_t rx_buffer;
uint8_t rx_buf[100];//接收到的指令臨時存放緩沖區
uint8_t rx_buf_index = 0;//控制數據往buf里邊存儲的順序
_Bool Start_Flag;//起始位判斷void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if((rx_buffer == 0x6B)&&(rx_buf_index == 0)){Uart_Rev_Data_Delay_Time = uwTick;//接收到第一個數據啟動計時		Start_Flag = 1;}if(Start_Flag == 1){		rx_buf[rx_buf_index] = rx_buffer;rx_buf_index++;		}	HAL_UART_Receive_IT(&huart1, (uint8_t *)(&rx_buffer), 1);	
}
串口數據處理
uint8_t Ctrl_Uart_Send_Time_Data_Times = 0;// 控制只允許到鬧鐘時間后只上報一次
__IO uint32_t Uart_Rev_Data_Delay_Time = 0;//控制串口接收數據的等待時間
_Bool Start_Flag;//起始位判斷uint16_t counter = 0;
uint8_t str[40];
uint8_t rx_buffer;
uint8_t rx_buf[100];//接收到的指令臨時存放緩沖區
uint8_t rx_buf_index = 0;//控制數據往buf里邊存儲的順序void Usart_Proc(void){if((uwTick -  uwTick_Usart_Set_Point)<30)	return;//減速函數uwTick_Usart_Set_Point = uwTick;//鬧鐘時間到if((H_M_S_Time.Hours == Clock_Comp_Ctrl[0]&&(H_M_S_Time.Minutes == Clock_Comp_Ctrl[1]&&(H_M_S_Time.Seconds == Clock_Comp_Ctrl[2])))){//控制只發送一次數據if(Ctrl_Uart_Send_Time_Data_Times == 0){Ctrl_Uart_Send_Time_Data_Times = 1;sprintf(str, "%4.2f+%3.1f+%02d%02d%02d\n", R37_Voltage, (k_int*0.1), (unsigned int)H_M_S_Time.Hour, (unsigned int)H_M_S_Time.Minute, (unsigned int)H_M_S_Time.Second);HAL_UART_Transmit(&huart1, (unsigned char *) str, strlen(strlen), 50);}}else//當時間變化或者控制值變化,兩者不等的時候,恢復下一次數據發送允許。Ctrl_Uart_Send_Time_Data_Times = 0;//串口接收的數據處理if(((uwTick - Uart_Rev_Data_Delay_Time)<=300)&&(uwTick - Uart_Rev_Data_Delay_Time)>=200)//200ms~300ms之內處理數據{if(rx_buf_index == 6)	//接收到6個數據{if((rx_buf[0] == 0x6B)&&(rx_buf[1] == 0x30)&&(rx_buf[2] == 0x2E)&&(rx_buf[4] == 0x5C)&&(rx_buf[5] == 0x6E)){if((rx_buf[3]>=0x31)&&(rx_buf[3]<=0x39)){k_int = rx_buf[3] - 0x30;sprintf(str, "OK\n");HAL_UART_Transmit(&huart1, (unsigned char *) strlen, strlen(strlen), 50);iic_24c02_write(&k_int, 0, 1);}}}rx_buf_index = 0;Start_Flag = 0;}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if((rx_buffer == 0x6B)&&(rx_buf_index == 0)){Uart_Rev_Data_Delay_Time = uwTick;//接收到第一個數據啟動計時		Start_Flag = 1;}if(Start_Flag == 1){		rx_buf[rx_buf_index] = rx_buffer;rx_buf_index++;		}	HAL_UART_Receive_IT(&huart1, (uint8_t *)(&rx_buffer), 1);	
}

發送數據沒啥好說的,而接收?"k0.x\n" 需要注意,總共就6個元素:

  • 檢查數據是否符合特定格式:

    • 0x6B?對應ASCII字符 'k'

    • 0x30?對應ASCII字符 '0'

    • 0x2E?對應ASCII字符 '.'

    • 0x5C?對應ASCII字符 ''

    • 0x6E?對應ASCII字符 'n'

除了 buf[3],其余都要檢查。

最后?使用?iic_24c02_write?將k的數值寫到k_int。

3.4 RTC

在前面,我已經定義過這兩個變量了,這里稍微再提一下。

RTC_TimeTypeDef H_M_S_Time;
RTC_DateTypeDef Y_M_D_Date;HAL_RTC_GetTime(&hrtc,&time,RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc,&date,RTC_FORMAT_BIN);

3.5 ADC

uint16_t getADC1(void)
{uint16_t adc = 0;HAL_ADC_Start(&hadc1);adc = HAL_ADC_GetValue(&hadc1);return adc;
}
uint16_t getADC2(void)
{uint16_t adc = 0;HAL_ADC_Start(&hadc2);adc = HAL_ADC_GetValue(&hadc2);return adc;
}

3.6 RCC

這部分,沒有什么需要用戶自己編寫的地方

3.7 I2C

void iic_24c02_write(uint8_t* pucBuf, uint8_t ucAddr, uint8_t ucNum)
{I2CStart();I2CSendByte(0xa0);I2CWaitAck();I2CSendByte(ucAddr);I2CWaitAck();while(ucNum--){I2CSendByte(*pucBuf++);I2CWaitAck();}I2CStop();HAL_Delay(500);
}
void iic_24c02_read(uint8_t* pucBuf, uint8_t ucAddr, uint8_t ucNum)
{I2CStart();I2CSendByte(0xa0);I2CWaitAck();I2CSendByte(ucAddr);I2CWaitAck();I2CStart();I2CSendByte(0xa1);I2CWaitAck();while(ucNum--){*pucBuf++=I2CReceiveByte();if(ucNum)I2CSendAck();elseI2CSendNotAck();}I2CStop();
}

4. 代碼規范

4.1 MAIN

main.c 頭文件

系統文件和Cube自動配置的:

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "rtc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include <stdio.h>   // 提供 sprintf()
#include <string.h>  // 提供 strlen()

第三方導入文件:

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "lcd.h"
#include "i2c_hal.h"
/* USER CODE END Includes */

結構體變量

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
RTC_TimeTypeDef H_M_S_Time;
RTC_DateTypeDef Y_M_D_Date;/* USER CODE END PTD */

用戶定義的全局變量

//*減速變量
__IO uint32_t uwTick_Key_Set_Point = 0;//控制Key_Proc的執行速度
__IO uint32_t uwTick_Led_Set_Point = 0;//控制Led_Proc的執行速度
__IO uint32_t uwTick_Lcd_Set_Point = 0;//控制Lcd_Proc的執行速度
__IO uint32_t uwTick_Usart_Set_Point = 0;//控制Usart_Proc的執行速度//*按鍵掃描專用變量
uint8_t ucKey_Val, unKey_Down, ucKey_Up, ucKey_Old;//*LED專用變量
uint8_t ucLed;//*LCD顯示專用變量
uint8_t Lcd_Disp_String[21];//最多顯示20個字符//*串口專用變量
uint16_t counter = 0;
char str[40];
uint8_t rx_buffer;
uint8_t rx_buf[100];//接收到的指令臨時存放緩沖區
uint8_t rx_buf_index = 0;//控制數據往buf里邊存儲的順序//用戶自定義變量區
uint8_t Interface_Num;//0x00-顯示界面,0x10-設置上報時間的小時,0x11-設置分鐘,0x12-設置秒。
float R37_Voltage;
uint8_t k_int = 1;
uint8_t LED_Ctrl = 0;// 0-打開,1關閉,控制LED報警功能
uint8_t Clock_Comp_Disp[3] = {0,0,0};//鬧鐘比較值的初值(顯示專用)
uint8_t Clock_Comp_Ctrl[3] = {0,0,0};//鬧鐘比較值的初值(控制專用)
__IO uint32_t uwTick_SETTING_TIME_Set_Point = 0;//控制待設置的時間數值閃爍
uint8_t SETTING_TIME_Ctrl = 0;// 0-亮,1-滅,控制時間設置界面的待設置值的閃爍功能
uint8_t Ctrl_Uart_Send_Time_Data_Times = 0;// 控制只允許到鬧鐘時間后只上報一次
__IO uint32_t Uart_Rev_Data_Delay_Time = 0;//控制串口接收數據的等待時間
_Bool Start_Flag;//起始位判斷
__IO uint32_t uwTick_LED_bulingbuling_Set_Point = 0;//控制LED報警閃爍的打點變量

函數聲明

/* USER CODE BEGIN PFP */
void Key_Proc(void);
void Led_Proc(void);
void Lcd_Proc(void);
void Usart_Proc(void);/*這部分封裝到BSP中*/
//uint8_t Key_Scan(void);
//void LED_Disp(uint8_t ucLed);
//void iic_24c02_write(uint8_t* pucBuf, uint8_t ucAddr, uint8_t ucNum);/* USER CODE END PFP */

不過,我更習慣將函數聲明放在 main.h 中。

4.2 BSP

gpio

LED的?void LED_Disp(uint8_t ucLed) 和 KEY的?uint8_t Key_Scan(void) 可以封裝到 gpio.c 中。

//gpio.h
/* USER CODE BEGIN Prototypes */
uint8_t Key_Scan(void);
void LED_Disp(uint8_t ucLed);
/* USER CODE END Prototypes *///gpio.c
/* USER CODE BEGIN 2 */
//LED掃描
void LED_Disp(uint8_t ucLed)
{//**將所有的燈熄滅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的數值點亮相應的燈HAL_GPIO_WritePin(GPIOC, ucLed<<8, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);	
}//按鍵掃描
uint8_t Key_Scan(void)
{uint8_t key_val=0;if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==GPIO_PIN_RESET){key_val=1;}if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==GPIO_PIN_RESET){key_val=2;}if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)==GPIO_PIN_RESET){key_val=3;}if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_RESET){key_val=4;}return key_val;
}
/* USER CODE END 2 */

ADC

//adc.h
/* USER CODE BEGIN Prototypes */
uint16_t getADC2(void);
uint16_t getADC1(void);
/* USER CODE END Prototypes *///adc.c
/* USER CODE BEGIN 1 */
uint16_t getADC1(void)
{uint16_t adc = 0;HAL_ADC_Start(&hadc1);adc = HAL_ADC_GetValue(&hadc1);return adc;
}
uint16_t getADC2(void)
{uint16_t adc = 0;HAL_ADC_Start(&hadc2);adc = HAL_ADC_GetValue(&hadc2);return adc;
}
/* USER CODE END 1 */

I2C

//i2c_hal.h
void iic_24c02_read(uint8_t* pucBuf, uint8_t ucAddr, uint8_t ucNum);
void iic_24c02_write(uint8_t* pucBuf, uint8_t ucAddr, uint8_t ucNum);//i2c_hal.c
void iic_24c02_write(uint8_t* pucBuf, uint8_t ucAddr, uint8_t ucNum)
{I2CStart();I2CSendByte(0xa0);I2CWaitAck();I2CSendByte(ucAddr);I2CWaitAck();while(ucNum--){I2CSendByte(*pucBuf++);I2CWaitAck();}I2CStop();HAL_Delay(500);
}void iic_24c02_read(uint8_t* pucBuf, uint8_t ucAddr, uint8_t ucNum)
{I2CStart();I2CSendByte(0xa0);I2CWaitAck();I2CSendByte(ucAddr);I2CWaitAck();I2CStart();I2CSendByte(0xa1);I2CWaitAck();while(ucNum--){*pucBuf++=I2CReceiveByte();if(ucNum)I2CSendAck();elseI2CSendNotAck();}I2CStop();
}

其他

像 LCD、UART、TIM、RTC 就不用封裝了,在 Main 中實現即可。

四、測試

燒錄完,測試時,會發現設置時間時,閃爍的位置不對。

應該把 Lcd_Proc 的時間設置區的控制閃爍代碼進行更改。

當然如果要居中顯示,就要看看自己整了多少空格。

    // 根據當前設置項閃爍對應位置if (SETTING_TIME_Ctrl == 0x1)  // 閃爍狀態{switch (Interface_Num){case 0x10:  // 設置時(閃爍 HH 部分)Lcd_Disp_String[3] = ' ';  // 第1個數字Lcd_Disp_String[4] = ' ';  // 第2個數字break;case 0x11:  // 設置分(閃爍 MM 部分)Lcd_Disp_String[6] = ' ';  // 第1個數字Lcd_Disp_String[7] = ' ';  // 第2個數字break;case 0x12:  // 設置秒(閃爍 SS 部分)Lcd_Disp_String[9] = ' ';  // 第1個數字Lcd_Disp_String[10] = ' '; // 第2個數字break;default:break;}}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/73645.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/73645.shtml
英文地址,請注明出處:http://en.pswp.cn/web/73645.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

第十二篇《火攻篇》:一把火背后的戰爭哲學與生存智慧

《孫子兵法》作為人類歷史上最早的軍事戰略經典&#xff0c;其思想穿透了2500年的時空&#xff0c;至今仍在政治、商業乃至個人決策領域閃耀光芒。第十二篇《火攻篇》看似聚焦于具體的戰術手段&#xff0c;實則蘊含了深刻的戰爭倫理與生存哲學。本文解讀這一篇章如何用一把火點…

word光標一直閃的解決辦法

在選項里&#xff0c;打開首選項&#xff0c;&#xff08;如果打不開&#xff0c;可以新建一個word也許就可以&#xff0c;實在不行只能靠眼疾手快&#xff0c;趁他還沒閃趕緊點&#xff09; 選COM加載項&#xff0c;在里面取消勾選MicrosoftOfficePLUS

修改菜品-01.需求分析與設計

一.需求分析與設計 修改時要首先回顯 設計時我們要設計哪些接口&#xff1f; 根據id查詢菜品接口設計&#xff1a; 我們要根據id進行查詢&#xff0c;因此在這里面id被作為路徑參數。使用注解PathVariable。在查詢菜品時&#xff0c;要將對應的口味也查出來&#xff0c;因此還…

Oracle到達夢數據庫遷移:技術要點與實踐分享

一、達夢數據庫簡介 達夢數據庫(DM,Dameng Database)是國內自主研發的具有自主知識產權的大型通用數據庫管理系統,具備以下顯著特點: 1.高性能:高效的存儲與計算分離架構:達夢數據庫采用先進的存儲與計算分離架構,能夠根據業務需求靈活分配存儲和計算資源,大大提高了…

Vue動態綁定:文本框、單選按鈕、下拉列表、多選按鈕

Vue 指令系列文章: 《Vue插值:雙大括號標簽、v-text、v-html、v-bind 指令》 《Vue指令:v-cloak、v-once、v-pre 指令》 《Vue條件判斷:v-if、v-else、v-else-if、v-show 指令》 《Vue循環遍歷:v-for 指令》 《Vue事件處理:v-on 指令》 《Vue表單元素綁定:v-model 指令》…

動態IP與靜態IP該如何選?

一、當IP地址成為"網絡身份" 2023年亞馬遜封號潮中&#xff0c;某杭州賣家因登錄IP頻繁切換&#xff08;早8點在紐約&#xff0c;午間瞬移到東京&#xff09;&#xff0c;觸發平臺風控導致賬號凍結。這類"時空錯亂癥"揭示了跨境電商的生存法則&#xff1a…

【機器學習】——機器學習基礎概念

摘要 本文主要介紹了機器學習的基礎概念和典型過程。一個完整的機器學習過程包括數據收集、數據預處理、數據集劃分、選擇模型、訓練模型、模型評估、模型優化和模型部署等關鍵步驟。在數據收集階段&#xff0c;要獲取足夠且高質量的數據&#xff1b;數據預處理包括數據清理、…

麒麟信安全國產化智算一體機與海光C86芯片+ 海光DCU卡完成兼容性適配!

近日&#xff0c;麒麟信安全國產化智算一體機與國產海光C86芯片、海光DCU卡完成兼容性適配&#xff01; 在數字化轉型的浪潮中&#xff0c;智能辦公已成為企業提升效率、降低成本的重要手段&#xff0c;如何快速、高效地部署智能辦公解決方案&#xff0c;成為許多企業面臨的挑…

Axure設計之中繼器表格——拖動列調整位置教程(中繼器)

一、原理介紹 實現表格列的拖動排序&#xff0c;主要依賴Axure的動態面板和中繼器兩大核心功能&#xff1a; 動態面板交互控制 將表格的列標題封裝在動態面板中&#xff0c;通過拖拽事件&#xff08;開始、移動、結束&#xff09;捕捉用戶操作 在拖拽過程中實時計算鼠標位置&…

Vue2項目打包后,某些圖片被轉換為base64導致無法顯示

提示&#xff1a;以下是本篇文章正文內容&#xff0c;下面案例可供參考 Vue2項目打包后&#xff0c;某些圖片被轉換為base64導致無法顯示 1.為什么有些圖片會被轉成base64&#xff0c;而其他的卻正常輸出到dist/img目錄下&#xff1f; 因為Vue CLI默認可能會對小于某個閾值的…

node-red dashboard

安裝&#xff1a; npm install node-red-dashboard 訪問&#xff1a; http://127.0.0.1:1880/ui 1. 創建一個新的 Dashboard 頁面: 在 Node-RED 編輯器中&#xff0c;拖動一個 ui_dashboard 節點到工作區&#xff0c;并將其連接到你的數據流。 2. 配置 Dashboard 節點: 雙擊…

《深入探究:數字類型轉換為指定格式字符串的奧秘》

在計算機編程的世界里&#xff0c;數據就如同流淌在系統脈絡中的血液&#xff0c;而數據類型則是決定其形態與行為的關鍵基因。將數字類型轉換為字符串類型并指定格式&#xff0c;這一看似基礎的操作&#xff0c;實則蘊含著豐富的技術內涵與應用價值&#xff0c;廣泛滲透于數據…

人體細粒度分割sapiens 實戰筆記

目錄 sapiens 分割示例: 分割config文件: 依賴項: mmcv安裝 測試 cnn和ops一起測試: 報錯: 保存圖片代碼: 人體box裁剪擴大,不裁剪擴大效果很差 sapiens https://github.com/facebookresearch/sapiens 分割示例: https://github.com/facebookresearch/sapie…

【cocos creator 3.x】3Dui創建,模型遮擋ui效果

官方文檔&#xff1a;https://docs.cocos.com/creator/3.8/manual/zh/ui-system/components/editor/ui-model.html 1、3Dui創建 創建label&#xff0c;默認會添加canvas根節點和2dCamera 將Camera刪除&#xff0c;canvas上組建去除cc.Canvas&#xff0c;cc.widget&#xff0…

從零開始跑通3DGS教程:介紹

寫在前面 本文內容 本文所屬《從零開始跑通3DGS教程》系列文章&#xff0c;將實現從原始圖像(有序、無序)數據開始&#xff0c;經過處理(視頻抽幀成有序)&#xff0c;SFM&#xff0c;3DGS訓練、編輯、渲染等步驟&#xff0c;完整地呈現從原始圖像到新視角合成的全部流程&#x…

車架號查詢車牌號接口如何用Java對接

一、什么是車架號查詢車牌號接口&#xff1f; 車架號查詢車牌號接口&#xff0c;即傳入車架號&#xff0c;返回車牌號、車型編碼、初次登記日期信息。車架號又稱車輛VIN碼&#xff0c;車輛識別碼。 二、如何用Java對接該接口&#xff1f; 下面我們以阿里云接口為例&#xff0…

SvelteKit 最新中文文檔教程(12)—— 高級路由

前言 Svelte&#xff0c;一個語法簡潔、入門容易&#xff0c;面向未來的前端框架。 從 Svelte 誕生之初&#xff0c;就備受開發者的喜愛&#xff0c;根據統計&#xff0c;從 2019 年到 2024 年&#xff0c;連續 6 年一直是開發者最感興趣的前端框架 No.1&#xff1a; Svelte …

Ubuntu系統保姆級Paperless-ngx部署指南:零基礎實現文檔云端化管理

文章目錄 前言1.關于Paperless-ngx2.Docker部署3.簡單使用paperless4.安裝cpolar內網穿透5. 配置公網地址6. 配置固定公網地址總結 前言 在當今快節奏的辦公環境中&#xff0c;文檔管理成為了一個不可忽視的問題。想象一下這樣的場景&#xff1a;你需要一份重要的合同&#xf…

PostgREST實現DBaaS(數據庫即服務)

目錄 配置使用 驗證 token使用 上文部署高可用PostgreSQL14集群后&#xff0c;本文介紹PostgREST&#xff0c;以及如何基于PostgREST實現數據庫即服務&#xff0c;PostgREST可以在 PostgreSQL 數據庫上通過解析數據庫結構&#xff08;如表、視圖、存儲過程、權限等&#xff…

基于yolov11的鐵路軌道鐵軌缺陷檢測系統python源碼+pytorch模型+評估指標曲線+精美GUI界面

【算法介紹】 基于YOLOv11的鐵路軌道鐵軌缺陷檢測系統是一種高效、準確的自動化檢測技術&#xff0c;專門用于識別和檢測鐵軌上的各種缺陷。該系統利用YOLOv11這一先進的深度學習模型&#xff0c;實現了對Corrugation&#xff08;波紋磨耗&#xff09;、Spalling&#xff08;剝…