STM32 Cubemx實現串口通信、I2C與GPIO的綜合應用

項目目標

  1. 通過按鍵,按下的值能夠串口接受並顯示出來,
  2. 串口發送數字,使用數碼管顯示數字。
  3. 將串口發送的數字使用I2C寫入EEPROM,按復位鍵並能夠讀出來。
    效果演示
#### 使用模塊 串口通信 I2C 鍵盤 數碼管 查看原理圖,找到相應的引腳 這個可以參考前面的文章 每個模塊都單獨講了,這個項目綜合功能使用

CubeMx配置

  1. 將數碼管和鍵盤對應的GPIO口進行相應的設置
    鍵盤使用掃描法 行和列 分別設爲input 和output 數碼管設爲output
    enter description here
  2. 使用USART1 並進行相應的配置
    enter description here
    NVIC Settings處 進行使能 ENable選中 打開中斷
  3. I2C配置
    配置時鐘 設置兩個引腳 設置I2C參數
    (這個地方圖參考 STM32 I2C介紹及cubemx配置)

代碼設計

  1. 添加數碼管 和鍵盤 封裝好的代碼
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}
};
  1. 一些變量聲明
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; // 獲取到的值的長度
  1. 由於 按鍵值是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;
}
  1. 掃描鍵盤獲取到的鍵值直接進行處理 使用 中斷髮送 到串口
    (掃描法鍵盤 講過 下面的處理有註釋)
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);
  1. 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學習教程

  1. STM32 cubemx keil5搭建學習環境
  2. 使用STM32 cubemx keil5實現led燈與數碼管控制
  3. 基於STM32 CubeMx keil5實現鍵盤的應用
  4. 基於STM32 CubeMx keil5實現串口通信 I2C與GPIO綜合應用
  5. 基於STM32 CubeMx keil5實現AD轉換獲取溫度
  6. 基於STM32 CubeMx keil5 學習使用I2C
  7. 基於STM32 CubeMx keil5 學習使用串口通信
  8. 基於STM32 CubeMx keil5應用定時器
  9. 基於STM32 cubemx keil5學習使用中斷
  10. 基於STM32 cubemx keil5綜合應用實現溫度控制系統
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章