一、工程模版創建流程
第一步?創建新項目
第二步?選擇型號和管腳封裝
?第三步 RCC使能? ?外部時鐘,高速外部時鐘
第四步晶振時鐘配置?
由數據手冊7.1可知外部晶振頻率為24MHz? 最后一項設置為80
按下回車他會自動配置時鐘
?第五步,如果不勾選可能程序只會下載一次到時候不好找問題
第6步 名字和路徑不能有中文
?第七步bsp為創建的程序存放的文件
八創建一個新組
注意程序只能寫在USER CODE BEGIN include 和user code end include
9Debug設置?點擊確定板載調試器?
?
?二、點亮一顆LED燈
原理圖
PD2鎖存器控制端口
第一步、打開PC8~15的接口配置為output模式
且選中管腳output設置為HIGH,PD2低電平時候為開,防止別的引腳沖突?
點擊生成即可
第二步 創建兩個文件led.c和led.h
定義縮寫? 在main.h函數內typedef unsigned char? uchar
頭文件位置要在BEGIN和END之間
?第三步、引用頭文件配置,這步是點擊魔術棒
?
案例程序----點亮led
main
/----------------------------------main.h-------------------------------/
/* USER CODE BEGIN Includes */
typedef unsigned char uchar;
typedef unsigned int uint;/* USER CODE END Includes */
/----------------------------------main.h-------------------------------/
頭文件
/* USER CODE BEGIN Includes */
#include "led.h"
/* USER CODE END Includes */
?主函數
LED_Disp(0x00);//LED初始化/* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */LED_Disp(0x02);HAL_Delay(500);LED_Disp(0x00);HAL_Delay(1000); }/* USER CODE END 3 */
led
/-----------------------------------led.h---------------------------------/
#ifndef __LED_H__
#define __LED_H__#include "main.h"
void LED_Disp(uchar dsLED);#endif
/-----------------------------------led.c---------------------------------/
#include "led.h"void LED_Disp(uchar dsLED)
{HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);//先將所有引腳設為高電平由原理圖設計HAL_GPIO_WritePin(GPIOC,dsLED << 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);}
三、lcd相關配置及代碼案例
LCD原理圖
?參考和移植官方的案例程序
第一步、引腳配置
全部配置為output
配置完引腳后點擊GENERATE CODE即可無需其他操作
第二步、將這兩個頭文件復制到
在給的案例路徑下將lcd.c、fonts、lcd.h也復制到bsp路徑下面
?第三步、添加頭文件
官方案例程序?
使用這種格式的顏色背景方便機器閱卷?背景色要求
? ? ? ??
案例程序----lcd顯示
添加lcd
/--------------------------------main.c----------------------------/
頭文件
/* USER CODE BEGIN Includes */
#include "led.h"
#include "lcd.h"
#include "stdio.h"
/* USER CODE END Includes */
?主函數
sprintf函數打印到字符串中
(要注意字符串的長度要足夠容納打印的內容,否則會出現內存溢出),而printf函數打印輸出到屏幕上。sprintf函數在我們完成其他數據類型轉換成字符串類型的操作中應用廣泛。
3、sprintf函數的格式:
int sprintf( char *buffer, const char *format [, argument,…] );? ? ? ?
/* Initialize all configured peripherals */MX_GPIO_Init();/* USER CODE BEGIN 2 */LED_Disp(0x00);//LED初始化LCD_Init();//LCD初始化LCD_Clear(Black);LCD_SetBackColor(Black);LCD_SetTextColor(White);/* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */LED_Disp(0x02);HAL_Delay(500);LED_Disp(0x00);HAL_Delay(1000);char text[30];uint i = 5;sprintf(text," CNBR:%d ",i);LCD_DisplayStringLine(Line9, (uint8_t *)text);}/* USER CODE END 3 */
三、按鍵配置
按鍵原理圖
第一步、引腳配置
引腳設置為input
第二步 模式設置上下拉模式選擇上拉
第三步定時器配置?
隨便選擇一個定時器?
時鐘選擇外部時鐘80Mhz---為了達到非阻塞式延時消抖
分屏系數和自動重裝載值設置?
100HZ=10ms中斷一次??從0開始0~79是80個數
?計算延時時間實例
?中斷使能
點擊生成代碼即可
程序及環境配置
新建兩個文件-另存interrupt.c,interrupt.h保存地址為該文件路徑下的bsp中
?/----------------------------------------------interrupt.h------------------------------------/
interrupt
#ifndef __INTERRUPT_H__
#define __INTERRUPT_H__#include "main.h"
#include "stdbool.h"
struct keys
{uchar judge_sta;//按鍵判斷bool key_sta;bool single_flag;//確認被按下他為1
};void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);#endif
?/----------------------------------------------interrupt.c------------------------------------/
在一個具有多個按鍵的嵌入式設備按鍵檢測程序中,通過循環遍歷?key
?數組(改變?i
?的值從 0 到數組元素個數減 1),就可以依次獲取每個按鍵的?judge_sta
?狀態,判斷是否滿足某些條件來進一步確認按鍵是否有效按下或者是否進入了特定的操作判斷階段等。
-
case 0
?分支:- 邏輯描述:當?
key[i].judge_sta
?的值為?0
?時進入該分支。在這個分支里,有一個條件判斷語句?if(key[i].key_sta == 0)
,也就是當?key[i].key_sta
(表示按鍵當前基本狀態,0
?在這里可能意味著未按下或者非激活狀態等)也為?0
?時,會將?key[i].judge_sta
?的值更新為?1
。這可能意味著當按鍵初始處于某個默認的未激活且符合某種前置條件時(由?judge_sta
?為?0
?和?key_sta
?為?0
?共同界定),將其狀態推進到下一個階段或者設置為另一種待確認的中間狀態(用?judge_sta
?變為?1
?來表示)。 - 可能的應用場景示例:比如在一個設備啟動后,按鍵初始都處于默認未操作狀態,當檢測到按鍵沒有被按下(
key_sta
?為?0
)且其整體判斷狀態處于初始的?0
?階段時,就將其推進到一個準備檢測后續是否有按下動作的狀態階段,對應?judge_sta
?更新為?1
。
- 邏輯描述:當?
-
case 1
?分支:- 邏輯描述:當?
key[i].judge_sta
?等于?1
?時執行此分支邏輯。這里的條件判斷是?if(key[i].key_sta == 0)
,如果?key[i].key_sta
?為?0
(即按鍵此時處于未按下狀態),會執行兩個操作:一是將?key[i].judge_sta
?重置回?0
,可能表示此次針對該按鍵的操作周期結束或者恢復到初始的一種狀態等待下次操作;二是將?key[i].single_flag
?設置為?1
,根據之前結構體定義中對?single_flag
?的注釋理解(確認被按下它為?1
),這里雖然當前按鍵是未按下狀態,但可能是在滿足了之前從?judge_sta
?為?1
?階段的一些檢測邏輯后,確認了一次完整的按鍵操作過程(比如之前從初始狀態進入到?1
?階段后,又檢測到按鍵松開了,就認為這是一次完整操作),所以設置?single_flag
?為?1
?來標記這次操作已完成,可以供程序后續部分依據這個標志做相應處理。 - 可能的應用場景示例:在一個游戲控制按鍵的處理中,當按下某個按鍵后?
judge_sta
?變為?1
?表示正在檢測按下動作,然后松開按鍵(key_sta
?變為?0
),此時就可以認為完成了一次有效的按鍵操作,將?judge_sta
?回置到?0
?等待下次操作,同時設置?single_flag
?為?1
?通知程序去執行比如游戲角色對應動作等相關功能代碼。
- 邏輯描述:當?
-
case 2
?分支:- 邏輯描述:當?
key[i].judge_sta
?的值為?2
?進入該分支。這里的條件判斷是?if(key[i].key_sta == 1)
,即如果此時按鍵處于按下狀態(key_sta
?為?1
),會將?key[i].judge_sta
?的值設置為?0
。這或許意味著當按鍵處于該?2
?所代表的狀態階段時,如果又檢測到它被按下了,那就將其狀態重置回初始或者某個默認狀態(用?judge_sta
?變為?0
?表示),可能是出現了不符合預期的重復按下或者需要重新開始檢測該按鍵的情況等原因。 - 可能的應用場景示例:在一個具有按鍵組合功能的設備中,如果某個按鍵單獨按下去后進入了?
judge_sta
?為?2
?的特定組合檢測狀態,但隨后又檢測到它再次被按下不符合當前功能的按鍵操作邏輯,就將其狀態復位到?0
?以便重新正確地檢測后續操作。
- 邏輯描述:當?
#include "interrupt.h"struct keys key[4] = {0,0,0};void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance==TIM3){key[0].key_sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);key[1].key_sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);key[2].key_sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);key[3].key_sta = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);for(int i = 0;i<4;i++){switch (key[i].judge_sta){ case 0:{if(key[i].key_sta == 0) key[i].judge_sta=1;}break;case 1:{if(key[i].key_sta ==0){key[i].judge_sta=0;key[i].single_flag=1;}}break;case 2:{if(key[i].key_sta==1){key[i].judge_sta=0;}}break;case 3:{ }break;}}}
}
/---------------------------main.c--------------------------------------------/
main?
* USER CODE BEGIN Includes */
#include "led.h"
#include "lcd.h"
#include "stdio.h"
#include "interrupt.h"/* USER CODE BEGIN PTD */
extern struct keys key[];
/* USER CODE END PTD */
/-----------------------------main.c------------------------------------------/
int main(void)
{
/* USER CODE BEGIN 2 */LED_Disp(0x00);//LED初始化LCD_Init();//LCD初始化LCD_Clear(Black);LCD_SetBackColor(Black);LCD_SetTextColor(White);HAL_TIM_Base_Start_IT(&htim3); //定時器中斷/* USER CODE END 2 */while (1){
char text[30];uint i = 5;sprintf(text," CNBR:%d ",i);LCD_DisplayStringLine(Line9, (uint8_t *)text);//實現按鍵的功能//第一個按鍵if(key[0].single_flag==1){sprintf(text," key0down ");LCD_DisplayStringLine(Line8,(uint8_t *)text);key[0].single_flag=0;}if(key[1].single_flag==1){sprintf(text," key1down ");LCD_DisplayStringLine(Line8,(uint8_t *)text);key[1].single_flag=0;}}/* USER CODE END 3 */
}