項目目標
- 通過按鍵,按下的值能夠串口接受並顯示出來,
- 串口發送數字,使用數碼管顯示數字。
- 將串口發送的數字使用I2C寫入EEPROM,按復位鍵並能夠讀出來。
效果演示
CubeMx配置
- 將數碼管和鍵盤對應的GPIO口進行相應的設置
鍵盤使用掃描法 行和列 分別設爲input 和output 數碼管設爲output
- 使用USART1 並進行相應的配置
NVIC Settings處 進行使能 ENable選中 打開中斷 - I2C配置
配置時鐘 設置兩個引腳 設置I2C參數
(這個地方圖參考 STM32 I2C介紹及cubemx配置)
代碼設計
- 添加數碼管 和鍵盤 封裝好的代碼
struct GPIO_PACK{
GPIO_TypeDef * port;
uint16_t pin;
}; //數碼管 引腳對應的結構數組
struct GPIO_PACK segs[8]= {
{GPIOA,GPIO_PIN_15},
{GPIOA,GPIO_PIN_11},
{GPIOC,GPIO_PIN_9},
{GPIOC,GPIO_PIN_7},
{GPIOC,GPIO_PIN_8},
{GPIOA,GPIO_PIN_12},
{GPIOA,GPIO_PIN_8},
{GPIOC,GPIO_PIN_6},
} ;
struct GPIO_PACK bits[4]={
{GPIOD,GPIO_PIN_2},
{GPIOB,GPIO_PIN_4},
{GPIOB,GPIO_PIN_6},
{GPIOB,GPIO_PIN_7},
};
uint8_t shuzu[]={ //段碼
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,
0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e
};
void DisplayOnebit(uint8_t digtal,uint8_t bit){
uint8_t i;
for(i=0;i<8;i++){
HAL_GPIO_WritePin(segs[i].port,segs[i].pin,(GPIO_PinState)(shuzu[digtal]&(0x01<<i)));
}
for(i=0;i<4;i++){
HAL_GPIO_WritePin(bits[i].port,bits[i].pin,(GPIO_PinState)(i!=bit));
}
}
void DisplayDigtal(uint16_t digtal){ // 調用這個函數使用數碼管
int a=0;
DisplayOnebit(digtal%10,0);
HAL_Delay(5);
if (digtal>=10){
DisplayOnebit(digtal/10%10,1);
HAL_Delay(5);
if (digtal>=100){
DisplayOnebit(digtal/100%10,2);
HAL_Delay(5);
if (digtal>=1000){
DisplayOnebit(digtal/1000%10,3);
HAL_Delay(5);
}
}
}
}
// 掃描鍵盤
struct GPIO_PACK lie[4]={
{GPIOB,GPIO_PIN_0},
{GPIOB,GPIO_PIN_1},
{GPIOB,GPIO_PIN_13},
{GPIOB,GPIO_PIN_12}
};
struct GPIO_PACK hang[4]={
{GPIOA,GPIO_PIN_6},
{GPIOA,GPIO_PIN_7},
{GPIOC,GPIO_PIN_4},
{GPIOC,GPIO_PIN_5}
};
- 一些變量聲明
uint8_t connctt2[25]="The Key is ";
uint8_t *receive;
uint8_t receive_str[4]="0"; // 串口發送接收到的值
int number=0;
int receive_kye; //掃描鍵盤獲取到的值
int get_key ; //串口發送的值 轉換爲int
int getkey_length=0; // 獲取到的值的長度
- 由於 按鍵值是int性 發送到串口是str性,從串口接收是str性,給數碼管展示是int性。
所以需要int和str來回轉換的代碼
void Int2Str(uint8_t* str, int intnum) // 將無符號整形整數intnum 轉換成字符 str
{
int i, Div = 1000000000, j = 0, Status = 0;
for (i = 0; i < 10; i++)
{
str[j++] = (intnum / Div) + '0';
intnum = intnum % Div;
Div /= 10;
if ((str[j-1] == '0') & (Status == 0))
{
j = 0;
}
else
{
Status++;
}
}
}
int str2int1( char* str) // 字符串轉整形
{
int temp = 0;
const char* p = str;
if(str == NULL) return 0;
if(*str == '-' || *str == '+')
{
str ++;
}
while( *str != 0)
{
if( *str < '0' || *str > '9')
{
break;
}
temp = temp*10 +(*str -'0');
str ++;
}
if(*p == '-')
{
temp = -temp;
}
return temp;
}
- 掃描鍵盤獲取到的鍵值直接進行處理 使用 中斷髮送 到串口
(掃描法鍵盤 講過 下面的處理有註釋)
void Displaykeying()
{
uint8_t i,j,s,key=0;uint8_t k=1;
for(i=0;i<4;i++)
{ HAL_GPIO_WritePin(lie[i].port,lie[i].pin,GPIO_PIN_RESET);
for(s=0;s<4;s++){
if(i!=s)
HAL_GPIO_WritePin(lie[s].port,lie[s].pin,GPIO_PIN_SET);}
for(j=0;j<4;j++)
{ k=HAL_GPIO_ReadPin(hang[j].port,hang[j].pin);
if(k==0)
HAL_Delay(5);
if(k==0)
switch(j)
{
case 0:key=j+1+i;break;
case 1:key=j+4+i;break;
case 2:key=j+7+i;break;
case 3:key=j+10+i;break;
}
}
}
if (key !=0)
{
number = 1;
uint8_t key_str[5]; // 按下的鍵值 轉換爲字符型
//connctt2 ="The Key is ";
strcpy(connctt2,"The Key is ");
DisplayDigtal(key);
Int2Str(key_str,key); //把receive_key 按下的鍵值 轉換爲字符型key_str
strncat(connctt2,key_str,10); //把key_str 添加到connctt2後面
HAL_Delay(500);
HAL_UART_Transmit_IT(&huart1,connctt2,25);// 串口發送 值
}else
number = 0;
}
上面的都放到主函數上面 方便調用
5. 從串口接收到值 使用中斷 對接收到的值處理
callback函數 (一般寫在主函數 後面)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
//getkey_length = 4-huart1.RxXferCount;
uint8_t received[4];
for(int i=0;i<4;i++)
received[i]=receive_str[i];
HAL_I2C_Mem_Write(&hi2c2, ADDR_AT24C02_Write, 0, I2C_MEMADD_SIZE_8BIT,received,4, 10000);
HAL_UART_Transmit(&huart1,received,4,50);
HAL_UART_Receive_IT(&huart1, receive_str,4);
}
接收到值以後 先使用I2C寫入 ,並使用串口發送 顯示出來
最後開啓下一個中斷接受
6. while循環中 處理的事情
一直掃描鍵盤調用掃描鍵盤的函數,能夠完成任務1,
將串口中斷獲取到的值轉換爲int型,並調用數碼管進行展示,完成任務2
Displaykeying();
get_key = str2int1(receive_str);
DisplayDigtal(get_key);
- I2C讀數據
定義在外面 讀和寫的起始位置
#define ADDR_AT24C02_Write 0xA0
#define ADDR_AT24C02_Read 0xA1
#define BufferSize 0x100
讀取EEPROM中的值,應該放在主函數中,while循環上面,每次開機能夠讀取到,並只讀一次
HAL_I2C_Mem_Read(&hi2c2, ADDR_AT24C02_Read,0,I2C_MEMADD_SIZE_8BIT,receive_str,4,10000);
在獲取到串口發送的值 就會寫入到EEPROM,在callback函數中。
完整代碼以及工程
芯片不同 ,對引腳的處理不同,這個需要注意
但是方法都是一樣的,代碼的處理思路都可以參考
GitHub鏈接
更多STM32學習教程
- STM32 cubemx keil5搭建學習環境
- 使用STM32 cubemx keil5實現led燈與數碼管控制
- 基於STM32 CubeMx keil5實現鍵盤的應用
- 基於STM32 CubeMx keil5實現串口通信 I2C與GPIO綜合應用
- 基於STM32 CubeMx keil5實現AD轉換獲取溫度
- 基於STM32 CubeMx keil5 學習使用I2C
- 基於STM32 CubeMx keil5 學習使用串口通信
- 基於STM32 CubeMx keil5應用定時器
- 基於STM32 cubemx keil5學習使用中斷
- 基於STM32 cubemx keil5綜合應用實現溫度控制系統