用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
  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值