485与串口的打开,读写操作一样,唯一的区别是485多了一个控制脚。控制脚低电平有效。
因为485是半双工工作模式,同一时间只能读或者只能写,所以设计之初就是当需要进行发送数据时,将控制引脚拉低,当发送完后需要立刻拉高,处于接收状态。 这里面临一个问题,发送完,控制脚拉高快了会导致对方数据接收不完全,如果控制脚拉高慢了,又会导致接收数据不完全。所以在应用层来控制这个脚非常不合适,只能在驱动里面修改。下面是驱动里面的修改方式:
static void sw_uart_stop_tx(struct uart_port *port)
{
struct sw_uart_port *sw_uport = UART_TO_SPORT(port);
if (sw_uport->ier & SUNXI_UART_IER_THRI) {
sw_uport->ier &= ~SUNXI_UART_IER_THRI;
SERIAL_DBG("stop tx, ier %x\n", sw_uport->ier);
serial_out(port, sw_uport->ier, SUNXI_UART_IER);
}
if(0 == strcmp("uart2", sw_uport->name))
{
char pin_name[8] = {0};
unsigned long config_set = 0;
unsigned long config_get = 0;
printk("sw_uart_stop_tx\n");
//msleep(5);
//__gpio_set_value(41,1);
int val=__gpio_get_value(41);
printk("value is %d\n",val);
//sunxi_gpio_to_name(GPIOB(9), pin_name);
//config_set = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC,1);
//pin_config_set(SUNXI_PINCTRL,pin_name,config_set);
//config_set = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT,1);
//pin_config_set(SUNXI_PINCTRL,pin_name,config_set);
//config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT,0XFFFF);
//pin_config_get(SUNXI_PINCTRL,pin_name,&config_get); //取GPIO值
//printk(" [%s] pin value: %ld\n",pin_name,SUNXI_PINCFG_UNPACK_VALUE(config_get));
}
}
static void sw_uart_start_tx(struct uart_port *port)
{
struct sw_uart_port *sw_uport = UART_TO_SPORT(port);
if(0 == strcmp("uart2", sw_uport->name))
{
char pin_name[8] = {0};
unsigned long config_set = 0;
unsigned long config_get = 0;
printk("sw_uart_start_tx\n");
__gpio_set_value(41,0);
int val=__gpio_get_value(41);
printk("value is %d\n",val);
//sunxi_gpio_to_name(GPIOB(9), pin_name);
//config_set = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC,1);
//pin_config_set(SUNXI_PINCTRL,pin_name,config_set);
//config_set = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT,0);
//pin_config_set(SUNXI_PINCTRL,pin_name,config_set);
//config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT,0XFFFF);
//pin_config_get(SUNXI_PINCTRL,pin_name,&config_get); //取GPIO值
//printk(" [%s] pin value: %ld\n",pin_name,SUNXI_PINCFG_UNPACK_VALUE(config_get));
}
if (!(sw_uport->ier & SUNXI_UART_IER_THRI)) {
sw_uport->ier |= SUNXI_UART_IER_THRI;
SERIAL_DBG("start tx, ier %x\n", sw_uport->ier);
serial_out(port, sw_uport->ier, SUNXI_UART_IER);
}
}
static void sw_uart_handle_tx(struct sw_uart_port *sw_uport)
{
struct circ_buf *xmit = &sw_uport->port.state->xmit;
int count;
if (sw_uport->port.x_char) {
serial_out(&sw_uport->port, sw_uport->port.x_char, SUNXI_UART_THR);
sw_uport->port.icount.tx++;
sw_uport->port.x_char = 0;
#ifdef CONFIG_SW_UART_DUMP_DATA
sw_uport->dump_buff[sw_uport->dump_len++] = sw_uport->port.x_char;
SERIAL_DUMP(sw_uport, "Tx");
#endif
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&sw_uport->port)) {
sw_uart_stop_tx(&sw_uport->port);
if(0 == strcmp("uart2", sw_uport->name)) // 此处只有接收到数据才会执行,猜测是处理接收的,这里还没有进一步测试
{
printk("sw_uart_handle_tx 1\n");
__gpio_set_value(41,1);
int val=__gpio_get_value(41);
printk("value is %d\n",val);
}
return;
}
count = sw_uport->port.fifosize / 2;
do {
#ifdef CONFIG_SW_UART_DUMP_DATA
sw_uport->dump_buff[sw_uport->dump_len++] = xmit->buf[xmit->tail];
#endif
serial_out(&sw_uport->port, xmit->buf[xmit->tail], SUNXI_UART_THR);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
sw_uport->port.icount.tx++;
if (uart_circ_empty(xmit)) {
break;
}
} while (--count > 0);
SERIAL_DUMP(sw_uport, "Tx");
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
spin_unlock(&sw_uport->port.lock);
uart_write_wakeup(&sw_uport->port);
spin_lock(&sw_uport->port.lock);
}
if (uart_circ_empty(xmit))
{
sw_uart_stop_tx(&sw_uport->port);
if(0 == strcmp("uart2", sw_uport->name)) //此处是关键
{
udelay(400);
printk("sw_uart_handle_tx 2\n");
__gpio_set_value(41,1);
int val=__gpio_get_value(41);
printk("value is %d\n",val);
}
}
}
经过测试在stop里面操作控制脚会导致数据发送不完整。所以改到sw_uart_handle_tx 这里面去操作。
备注:在stop里面加入msleep 或者使用SUNXI_PINCTRL的方式操作控制脚都会出现内核错误。
如果同时开启多个485串口,同时操作的时候仍然会偶尔出现数据发送不完全的情况。