iT邦幫忙

2021 iThome 鐵人賽

DAY 18
1

這是算是大家最常見串列通訊,他原理較簡單方便,現在韌體工程師在除錯或為簡單驗證資料,大家知道TX、RX主機和從機對接transmitter(TX)為發射端、receiver(RX)為接收端。
再來我介紹一下協議的部分吧,TX對接另個設備的RX只要兩邊的設定的鮑率相同就可以做溝通,這設定鮑率就類似像I2C的時脈線,那UART就只剩下資料線而已,那數據的格式就很簡單了啦,有點類似I2C。
資料格式:
https://ithelp.ithome.com.tw/upload/images/20211001/20141979BOiZYRZ71T.png
校驗位的話可有可無,擔心傳輸中會有偏差造成資料錯誤,可以選擇校驗位開啟。

STM32的UASRT是同步非同步收發,UART為非同步收發
UASRT可以全雙工的Data,UART就去掉同步,我們通常都用到UART而已
UART部分就沒這麼複雜了,來看看程式吧

"bsp_uart.h"

#ifndef __BSP_UART_H
#define __BSP_UART_H

#include "stm32f0xx.h"
#include "stdio.h"
#define DEBUG_USARTx                    USART2 
#define DEBUG_USART_CLK                 RCC_APB1Periph_USART2
#define DEBUG_USART_APBxClkCmd          RCC_APB1PeriphClockCmd
#define DEBUG_USART_BAUDRATE            9600

#define DEBUG_USART_GPIO_CLK            RCC_AHBPeriph_GPIOA
#define DEBUG_USART_GPIO_AHBClkCmd      RCC_AHBPeriphClockCmd

#define DEBUG_USART_TX_GPIO_PORT        GPIOA
#define DEBUG_USART_TX_GPIO_PIN         GPIO_Pin_2
#define DEBUG_USART_RX_GPIO_PORT        GPIOA
#define DEBUG_USART_RX_GPIO_PIN         GPIO_Pin_3

void DEBUG_USART_Config(void);
void Usart_SendString( USART_TypeDef * pUSARTx, char *str);
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);

這樣定義有個好處,移到其他UART口或著是移到其他型號MCU,只要來這邊做修改就好。
DEBUG_USART_Config:這是初始化UART外設IO口
Usart_SendString:發送字串
Usart_SendByte:發送1Byte的資料

"bsp_uart.c"

//bsp board support package
#include "bsp_uart.h"
void DEBUG_USART_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure; 
    
	DEBUG_USART_GPIO_AHBClkCmd(DEBUG_USART_GPIO_CLK,ENABLE);
	DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK,ENABLE);

	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_1;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
	
    GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_1);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_1);   
	
	USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_Init(DEBUG_USARTx,&USART_InitStructure);

	UART_NVIC_InitConfig();
	USART_ITConfig(DEBUG_USARTx,USART_IT_RXNE,ENABLE);
    
    USART_ClearFlag(DEBUG_USARTx,USART_FLAG_TC);
	USART_Cmd(DEBUG_USARTx,ENABLE);
}

可以看到上面,要先開UART的腳位的GPIO口復用功能,復用功能ST都設計好了,你只需要設定到復用功能AF多少就好了。
https://ithelp.ithome.com.tw/upload/images/20211001/20141979SzfUJzA7hT.png
我這邊是用PA2、PA3,所以復用AF1(紅框部分)

再來是發送的程式:

void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
  USART_SendData(pUSARTx,ch);
  while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
  unsigned int k=0;
  do 
  {
    Usart_SendByte( pUSARTx, *(str + k) );
    k++;
  } while(*(str + k)!='\0');
  while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
  {}
}

int fputc(int ch, FILE *f)
{
	/* 發送一個字節數據到串口 */
	USART_SendData(DEBUG_USARTx, (uint8_t) ch);
	/* 等待傳送完畢 */
	while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);		
	return (ch);
}
///重定向c库函数scanf到串口可使用scanf、getchar等函数
int fgetc(FILE *f)
{
	/* 等待串口输入数据 */
	while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
	return (int)USART_ReceiveData(DEBUG_USARTx);
}

看到int fputc跟int fgetc,這兩個函式就是可以讓UART傳送利用Printf做使用,接收用scanf,這樣看起來比較親切一點。
接下就在主程式就打printf TX就會發送啦,可以快速驗證自己的程式有沒有符合自己的預期~


上一篇
[DAY 17] _ST25DV16K 動態NFC/RFID tag
下一篇
[DAY 19] _ARM-M0-內核外設SysTick-寫個精準的Delay
系列文
基於ARM-M0架構MCU之落摔檢測韌體開發35
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言