文章目录[隐藏]
一、串口初始化 (主控芯片用的GD32f303rct6)
void usart_init()
{
/* 略 */
}
/***************** 发送一个字节 **********************/
/* 单独调用时要记得先使能485发送引脚,发送后切为接收模式 */
void usart_sendbyte(uint32_t usart_periph, uint8_t ch)
{
/* 发送一个字节数据到USART */
usart_data_transmit(usart_periph, ch);
/* 等待发送数据寄存器为空 */
while (usart_flag_get(usart_periph, USART_FLAG_TBE) == RESET);
}
/***************** 发送指定长度的字符串 **********************/
void rs485_send_data(uint8_t *str,uint32_t strlen )
{
unsigned int k=0;
rs485_mode_set(1); //切换为发送
do
{
usart_sendbyte(USART0, *(str + k));
k++;
} while(k < strlen);
///*yehuo de 加短暂延时,保证485发送数据完毕*/
//Delay(0xFFF); /* 短延时没用, 导致最后一个字节为0xff, 长延时不能接受 */
/* yuanzi de 等待发送完成 */
while (usart_flag_get(USART0, USART_FLAG_TC) == RESET); /* 有用 */
rs485_mode_set(0); //切换为接收模式
}
/* _485延时等待,切换收发模式时等待硬件完成 */
void rs485_delay()
{
__IO uint32_t count = 30;
for(;count!=0;count--);
}
/* 控制485模块收发模式 0:recv, 1:send*/
void rs485_mode_set(uint8_t mode)
{
rs485_delay();
if (mode)
gpio_bit_reset(GPIOA, GPIO_PIN_5); /* PA5是rs485收发模式控制引脚 */
else
gpio_bit_set(GPIOA, GPIO_PIN_5);
rs485_delay();
}
二、printf重定向到串口
/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
//rs485_mode_set(1); 不能在里面切模式, 有延时
usart_data_transmit(USART0, (uint8_t)ch);
while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
//rs485_mode_set(0);
return ch;
}
三、踩到的坑:
1. RS485使用串口输出任意长度字符串, 最后一个字节固定为FF(其他的字节偶尔乱码)
原因显然是最后一个字节没发出去, 网络上的解决方法:
- 多发一个空字符.
- 发完切模式前加延时, 1ms. 本人实测不同波特率需要不同的延时(1ms), 延时较长并且其他的字符也不稳定.
实际解决方法: 等发送完成标志
while (usart_flag_get(USART0, USART_FLAG_TC) == RESET); /* 有用 */
2. printf函数规律性乱码
其中一个原因同上, 另一个是: printf重定向问题, 不应该在int fputc(int ch, FILE *f)
里面切换RS485收发器工作模式, printf调用此函数每发送一个字符, 会调用4次rs485_dealy()
. 解决方法:
- 不用printf()函数
- 在printf()函数外面切换RS485收发器工作模式 (直观但啰嗦)
rs485_mode_set(1);
printf(); /* 加的log */
rs485_mode_set(0);
- 将上面3行代码封装成一个函数, 参数与
printf()
的一样, 貌似很难实现可变长度参数的传递, 挖坑待填: 可以参考rt-thread的rt_printk()
实现原理.
- 2022.1.8更新:
#define printk(fmt, args...) do{\
rs485_mode_set(1);\
printf(fmt, ##args);\
while (usart_flag_get(USART0, USART_FLAG_TC) == RESET);\
rs485_mode_set(0);\
} while (0)
- 1.26更新(未测试是否可用)
void u3_printf(const char* fmt, ...)
{
u16 i = 0;
u8 buffer[256];
va_list args;
va_start(args, fmt);
vsprintf(buffer, 255, fmt, args);
while ((i < 256) && (buffer[i]))
{
usart_sendbyte(USART3, buffer[i]); //发送数据到串口3
}
va_end(args);
}
版权声明:本文为CSDN博主「RYYB」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ponyma_/article/details/122178710
暂无评论