Files
FilmForge/Src/rs485.c
T

127 lines
4.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "rs485.h"
#include "gd32f4xx_usart.h"
#include "gd32f4xx_rcu.h"
#include "gd32f4xx_gpio.h"
#include "board_config.h"
#include "uart.h"
/* 独立接收环形缓冲区(与 debug 串口的 uart_ring_buffer 隔离),
采用"预留一格"区分空/满,最大可用容量为 RS485_RX_BUFFER_SIZE-1 */
static __IO uint8_t rs485_rx_buffer[RS485_RX_BUFFER_SIZE];
static __IO uint8_t rs485_write_index = 0;
static __IO uint8_t rs485_read_index = 0;
static inline uint32_t rs485_irq_save(void) {
uint32_t primask = __get_PRIMASK();
__disable_irq();
return primask;
}
static inline void rs485_irq_restore(uint32_t primask) {
if ((primask & 0x1) == 0) {
__enable_irq();
}
}
/**
* @brief 配置 RS485 收发引脚(PA9 TX / PA10 RX 复用,DE PA8 推挽输出)。
*/
static void rs485_gpio_config(void) {
/* 使能 GPIOA 和 USART0 时钟 */
rcu_periph_clock_enable(RS485_GPIO_RCU);
rcu_periph_clock_enable(RS485_RCU);
/* PA9 为 USART0_TX,PA10 为 USART0_RX(AF7) */
gpio_af_set(RS485_GPIO_PORT, GPIO_AF_7, RS485_TX_PIN | RS485_RX_PIN);
gpio_mode_set(RS485_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, RS485_TX_PIN | RS485_RX_PIN);
gpio_output_options_set(RS485_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, RS485_TX_PIN | RS485_RX_PIN);
/* DE 引脚为普通推挽输出,默认接收态 */
rcu_periph_clock_enable(RS485_DE_RCU);
gpio_mode_set(RS485_DE_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, RS485_DE_PIN);
gpio_output_options_set(RS485_DE_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, RS485_DE_PIN);
gpio_bit_reset(RS485_DE_PORT, RS485_DE_PIN);
}
void rs485_init(void) {
rs485_gpio_config();
/* 配置波特率、数据位、停止位等 */
usart_deinit(RS485_PHY);
usart_word_length_set(RS485_PHY, USART_WL_8BIT);
usart_stop_bit_set(RS485_PHY, USART_STB_1BIT);
usart_parity_config(RS485_PHY, USART_PM_NONE);
usart_baudrate_set(RS485_PHY, RS485_BAUDRATE);
usart_receive_config(RS485_PHY, USART_RECEIVE_ENABLE);
usart_transmit_config(RS485_PHY, USART_TRANSMIT_ENABLE);
usart_enable(RS485_PHY);
/* 使能接收非空中断 */
nvic_irq_enable(RS485_IRQ, 0, 0);
usart_interrupt_enable(RS485_PHY, USART_INT_RBNE);
}
void rs485_send(const uint8_t *data, uint16_t len) {
/* 进入发送态 */
gpio_bit_set(RS485_DE_PORT, RS485_DE_PIN);
for (uint16_t i = 0; i < len; i++) {
/* 等待发送缓冲区空 */
while (RESET == usart_flag_get(RS485_PHY, USART_FLAG_TBE)) {}
usart_data_transmit(RS485_PHY, data[i]);
}
/* 等待最后一字节移位完成,再切回接收态(避免截断尾字节) */
while (RESET == usart_flag_get(RS485_PHY, USART_FLAG_TC)) {}
/* 回到接收态 */
gpio_bit_reset(RS485_DE_PORT, RS485_DE_PIN);
}
uint8_t rs485_rx_available(void) {
uint8_t w = rs485_write_index;
uint8_t r = rs485_read_index;
return (uint8_t)((w + RS485_RX_BUFFER_SIZE - r) % RS485_RX_BUFFER_SIZE);
}
int rs485_rx_get(void) {
if (rs485_read_index == rs485_write_index) return -1; /* 空 */
uint8_t data = rs485_rx_buffer[rs485_read_index];
rs485_read_index = (rs485_read_index + 1) % RS485_RX_BUFFER_SIZE;
return data;
}
void rs485_process(void) {
while (rs485_rx_available() > 0) {
int b = rs485_rx_get();
if (b < 0) {
break;
}
/* 拉通阶段:原样回发 RS485,同时转发 debug 串口便于观察 */
rs485_send((const uint8_t *)&b, 1);
debug_uart_write((uint8_t)b);
}
}
void rs485_irq_handler(void) {
/* 处理USART0的接收中断 */
if (usart_interrupt_flag_get(RS485_PHY, USART_INT_FLAG_RBNE)) {
uint8_t data = usart_data_receive(RS485_PHY);
uint32_t primask = rs485_irq_save();
uint8_t next = (rs485_write_index + 1) % RS485_RX_BUFFER_SIZE;
if (next != rs485_read_index) {
/* 缓冲区未满 */
rs485_rx_buffer[rs485_write_index] = data;
rs485_write_index = next;
}
/* 缓冲满时丢弃 */
rs485_irq_restore(primask);
}
/* 处理USART0的空闲中断(帧间隔提示,后续协议解析用) */
if (usart_interrupt_flag_get(RS485_PHY, USART_INT_FLAG_IDLE)) {
usart_interrupt_flag_clear(RS485_PHY, USART_INT_FLAG_IDLE);
}
}