1. 程式人生 > >用STM32F103RCT6的普通IO口模擬串列埠的實驗

用STM32F103RCT6的普通IO口模擬串列埠的實驗

使用了STM32CubeMX及Keil (HAL庫)
材料:stm32開發板、USB轉TTL?CH340模組、杜邦線、st-link

實驗原理:

模擬了非同步半雙工通訊

波特率可變

起始位:1
資料位:8
停止位:1
(1個數據10位)
無校驗位

傳輸一個字元的時候先發送1位起始位,然後是8位資料位(從低位到高位),最後是一位停止位

用1個普通的GPIO口輸出(模擬TXD),模擬了以上傳送的高低電平,採用定時器延時(一個位對應的電平的持續時間為1000000/波特率 μs)
用1個普通的GPIO口中斷輸入(模擬RXD),模擬了接收,下降沿觸發中斷,採用定時器延時,大概在資料位中央採集1次電平資料

實驗設計:
使用了PA1作TXD,PA2作RXD,然後連到CH340模組再連到電腦
TIM2延時

實驗過程:

測試使用9600的波特率

一開始只實現了初始時傳送“hello”,以及環回測試的2位資料正確收發。。。

推斷PA1傳送功能應該成功了(然而經過邏輯分析儀檢測PA1傳送的一個位的延時達到106us左右,正常情況應該是104us),PA2接受功能有bug,一次只能正確接受2位資料,後面收到的都是錯誤的字元,推測是延時上時間誤差的問題,而且會自增像空格一樣的字元(經過邏輯分析儀的檢測其實是ascii碼為255的字元,多次測試發現應該是接受完所有字元後又觸發了中斷,然而後面都是高電平,所以就收到了這個字元)。。。

錯誤的結果:


然後根據推測改程式碼,把接收資料中的延時時間改小,忽略掉ascii碼為255的字元(簡單粗暴的方法。。。)

正確的結果:



STM32CubeMX中的主要設定:






主要程式碼(以下只有USER CODE BEGIN裡的程式碼):

/* USER CODE BEGIN Includes */
#include <string.h>
/* USER CODE END Includes */
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
uint32_t baudrate=9600;  //設定波特率,比如9600bps
uint8_t message[20]; //收到的字元存放的字元陣列
uint8_t length=0; //收到的字元數
uint8_t welcome[]="hello"; //要傳送的一個初始資訊
uint32_t bit_time;
/* USER CODE END PV */

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
void delay_us(uint32_t counter);
void transmitChar(uint8_t ch);
uint8_t receiveChar(void);
void transmitString(uint8_t a[]);
/* USER CODE END PFP */
  /* USER CODE BEGIN 1 */
bit_time=1000000/baudrate; //一個位的時間,單位us
  /* USER CODE END 1 */
  /* USER CODE BEGIN 2 */
transmitString(welcome); //傳送初始資訊
  /* USER CODE END 2 */

/* USER CODE BEGIN 4 */

//延時counter(us)
void delay_us(uint32_t counter){  
	counter++;
	HAL_TIM_Base_Start(&htim2);
	__HAL_TIM_SET_COUNTER(&htim2,counter);
	while(counter>1){
		counter=__HAL_TIM_GET_COUNTER(&htim2); 
	}
	HAL_TIM_Base_Stop(&htim2);
}


//傳送字元
void transmitChar(uint8_t ch){
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,(GPIO_PinState)0);
	delay_us(bit_time);
	uint8_t i,temp;
	for(i=0;i<8;i++){
		temp=ch&0x01;
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,(GPIO_PinState)temp);
		delay_us(bit_time);
		ch>>=1;
	}
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,(GPIO_PinState)1);
	delay_us(bit_time);
}


//傳送字串
void transmitString(uint8_t a[]){
	uint8_t i,j;
	j=strlen(a);
	for(i=0;i<j;i++){
			transmitChar(a[i]);
		}
}


//接收字元
uint8_t receiveChar(void){
	uint8_t bit,i,ch=0;
	delay_us(bit_time*1.5);
	for(i=0;i<8;i++){
		bit=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_2);
		ch>>=1;
		if(bit){
			ch=ch|0x80;
		}
		
		delay_us(bit_time);
	}
	delay_us(bit_time*0.2);
	return ch;
}


//GPIO的中斷回撥函式
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(GPIO_Pin);
	uint8_t ch;
	ch=receiveChar();
	if(ch=='#'){
		uint8_t i;
		for(i=0;i<length;i++){
			transmitChar(message[i]);
		}
		length=0;
	}
	else if(ch!=255){
		message[length++]=ch;}
}

/* USER CODE END 4 */


實驗成果:

實現了19個字元以內的正確收發(20個元素的字元陣列,更多字元的接收沒有測試。。。)






參考資料:普通的  http://www.eeworld.com.cn/mcu/article_2016053126671.html