STM8S103系列IO口模拟串口通信(实现真正串口)

STM8s103f3p3单片机只有一个串口,有时候在实际项目中,我们需要用到多个串口来实现项目要求,此时,我们可以通过IO口来模拟串口通信,在实现项目需求的同时,还大大降低了成本。

实验原理

默认串口空闲状态为高电平,开始位为0,然后发送8个数据位,然后是奇偶校验位,停止位为高电平。数字电路中只有0、1两种状态,这是我们用IO口可以实现的,我们认为高电平是1,低电平是0。也就是说我们用只到了IO口的输出功能(对于实现TX功能的IO口而言),那么到底发多长时间的高电平呢?这是由TIMx定时器决定的,TIMx定时器通过计数器实现。这个时间取决于什么呢?取决于波特率。也就是说,只要我们初始化设置好了TIMx定时器我们就不需要考虑时间问题了。为方便我们现发送低位,然后逐渐右移来发送高位。如何判断发送完一个字节呢?我们认为10位为一个字节。如何判断发送玩所有的字节呢?我们使用一个缓存区(也就是数组)缓存区的字节发送完了我们就认为发送完了。

IO口配置

串口通信需要发送(TX)和接收(RX)两根通信线(半双工模式)。因此,我们需要将两个IO端口分别配置成TX和RX。

1.IO_TX发送配置:IO基本模式配置(具体请看前几期IO口配置博客),开启外部中断,触发模式设置为下降沿触发;
代码如下:

#define	VM_UART_TXD_PORT_OUT       PC_DDR|=1<<5 ;PC_CR1|=(1<<5 );PC_CR2 &=~(1<<5)//设定为输出
#define	VM_UART_TXD_PORT_IN        PC_DDR&=~(1<<5 );PC_CR1|=(1<<5 );PC_CR2&=~(1<<5 )//设定为输入

2.IO_RX发送配置:IO基本模式配置(具体请看前几期IO口配置博客),开启外部中断,触发模式设置为上升沿和下降沿触发
代码如下:

#define	VM_UART_RXD_PORT_IN        PB_DDR&=~(1<<4);PB_CR1|=(1<<4);PB_CR2&=~(1<
  • 1
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
STM32中,通过普通IO模拟串口通信,需要自己编写相关的发送和接收函数来实现数据的处理和解析。下面是一个示例代码,可以供你参考: ```c #include "stm32f1xx.h" #define UART_TX GPIO_PIN_9 // 发送引脚 #define UART_RX GPIO_PIN_10 // 接收引脚 #define BAUDRATE 9600 // 波特率 GPIO_InitTypeDef GPIO_InitStruct; void delay_us(uint32_t us) { uint32_t tickstart = HAL_GetTick(); uint32_t wait = us * (SystemCoreClock / 1000000U); while ((HAL_GetTick() - tickstart) < wait) { } } void UART_GPIO_Init(void) { __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Pin = UART_TX; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 配置发送引脚为输出模式 GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pin = UART_RX; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 配置接收引脚为输入模式 } void UART_SendByte(uint8_t data) { uint8_t i; HAL_GPIO_WritePin(GPIOA, UART_TX, GPIO_PIN_RESET); // 发送起始位 for (i = 0; i < 8; i++) { // 按位发送数据 if (data & 0x01) { HAL_GPIO_WritePin(GPIOA, UART_TX, GPIO_PIN_SET); } else { HAL_GPIO_WritePin(GPIOA, UART_TX, GPIO_PIN_RESET); } data >>= 1; delay_us(1000000 / BAUDRATE); } HAL_GPIO_WritePin(GPIOA, UART_TX, GPIO_PIN_SET); // 发送停止位 delay_us(1000000 / BAUDRATE); } uint8_t UART_ReceiveByte(void) { uint8_t data = 0; uint8_t i; while (HAL_GPIO_ReadPin(GPIOA, UART_RX) == GPIO_PIN_RESET) { // 等待接收起始位 } delay_us(1000000 / BAUDRATE / 2); // 延时半个波特率时钟周期,等待数据位 for (i = 0; i < 8; i++) { // 按位接收数据 data >>= 1; if (HAL_GPIO_ReadPin(GPIOA, UART_RX) == GPIO_PIN_SET) { data |= 0x80; } delay_us(1000000 / BAUDRATE); } while (HAL_GPIO_ReadPin(GPIOA, UART_RX) == GPIO_PIN_SET) { // 等待接收停止位 } return data; } int main(void) { HAL_Init(); UART_GPIO_Init(); // 初始化GPIO while (1) { UART_SendByte(0xAA); // 发送数据 uint8_t data = UART_ReceiveByte(); // 接收数据 } } ``` 在这个示例代码中,我们使用GPIOA的Pin9和Pin10分别模拟串口的发送和接收。在发送数据时,我们将发送引脚拉低,并按照位的顺序依次将数据输出到发送引脚上。在接收数据时,我们轮询接收引脚的电平状态,按照位的顺序将数据接收下来。需要注意的是,由于使用IO模拟串口的收发,在高速通讯时容易出现误码和数据丢失等问题,因此需要充分测试和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值