模式1
2-gpio-normal-uart-rs485-halfduplex
(2个gpio独立控制de/re, enable就是将相关gpio设置到active电平;不用uart控制器的rs485模式;uart控制器处于normal模式)
a, 默认re-en, de-dis,默认rs485-rx
b, 当要发送的时候,re-dis, de-enable, 然后uart-tx.
c, tx完成之后,de-dis; re-en,进入默认的rs485-rx模式。
模式2
1-gpio-normal-uart-rs485-halfduplex
这个模式的前提条件,外设器件的 de/re必须是相反极性的,比如de是高电平有效,re是低电平有效,则可以用一个gpio,来控制 de/re,此时de/re一定是互斥的。
(1个gpio控制de/re, enable就是将相关gpio设置到active电平;不用uart控制器的rs485模式;uart控制器处于normal模式)
a, re-en,进入rs485-rx模式 (re 通常是低电平有效,这一步就是 设置 re对应的gpio为低电平)
b, 当要发送的时候,设置gpio:re-disable, de-enable, 然后uart-tx.(re 通常是低电平有效,这一步就是 设置 re对应的gpio为高电平)
c, tx完成之后,de-disable; re-enable,进入默认的rs485-rx模式。(re 通常是低电平有效,这一步就是 设置 re对应的gpio为低电平)
模式3
rs485-software-halfduplex(de/re 独立输出)
(使能uart控制器的rs485模式; 通过uart模块内部reg来控制 de/re 信号)
a,使能uart控制器的 rs485模式,并按照电压转换芯片的特性,设置de/re polarity
b, 设置rs485的模式为 sw-half-duplex, 设置 de-timing寄存器; 设置 de/re turnaround 寄存器。
c, 默认为rs485-rx模式,设置 de-dis/re-en
d, 当要tx的时候,设置 de-en/re-dis
e, 发送完成,设置 de-dis/re-en
模式4
rs485-hardware-halfduplex(de/re 独立输出)
基本配置同模式3,但是设置 rs485模式为 hardware-halfduplex模式
a, 只要设置 de-en/rx-en 都为1,然后就不用管了,硬件实现半双工切换。
模式5:
使用纯硬件的办法实现RS485半双工功能,电路如图所示:
接收:
默认没有数据时,UART_TX为高电平,三极管导通,485芯片RE低电平使能,RO接收数据使能,此时从485AB口收到什么数据就会通过RO通道传到MCU,完成数据接收过程。
发送:
当发送数据时,UART_TX会有一个下拉的电平,表示开始发送数据,此时三极管截止,DE为高电平发送使能。当发送数据‘0’时,由于DI口连接地,此时数据‘0’就会传输到AB口 A-B<0,传输‘0’,完成了低电平的传输。当发送‘1’时,此时三极管导通,按理说RO使能,此时由于还处在发送数据中,这种状态下485处于高阻态,此时的状态通过A上拉B下拉电阻决定,此时A-B>0传输‘1’,完成高电平的传输。 3. 模块详细设计 3.1. 关键函数接口 3.1.1. uart_register_driver /*功能: uart_register_driver用于串口驱动uart_driver注册到内核(串口核心层)中,通常在模块初始化函数调用该函数。 *参数:drv:要注册的uart_driver *返回值:成功,返回0;否则返回错误码 */ int uart_register_driver(struct uart_driver *drv) 3.1.2. uart_unregister_driver /*功能:uart_unregister 用于注销我们已注册的uart_driver,通常在模块卸载函数调用该函数, *参数 : drv:要注销的uart_driver *返回值:成功返回0,否则返回错误码 */ void uart_unregister_driver(struct uart_driver *drv) 3.1.3. uart_add_one_port /*功能:uart_add_one_port用于为串口驱动添加一个串口端口,通常在探测到设备后(驱动的设备probe方法)调用该函数 *参数: * drv:串口驱动 * port:要添加的串口端口 *返回值:成功,返回0;否则返回错误码 */ int uart_add_one_port(struct uart_driver *drv,struct uart_port *port) 3.1.4. uart_remove_one_port /*功能:uart_remove_one_port用于删除一个已经添加到串口驱动中的串口端口,通常在驱动卸载时调用该函数 *参数: * drv:串口驱动 * port:要删除的串口端口 *返回值:成功,返回0;否则返回错误码 */ int uart_remove_one_port(struct uart_driver *drv,struct uart_port *port) 3.1.5. uart_write_wakeup /*功能:uart_write_wakeup唤醒上层因串口端口写数据而堵塞的进程,通常在串口发送中断处理函数中调用该函数 *参数: * port: 需要唤醒写堵塞进程的串口端口 */ void uart_write_wakeup(struct uart_port *port) 3.1.6. uart_suspend_port /*功能:uart_suspend_port用于挂起特定的串口端口 *参数: * drv:要挂起的串口端口锁所属的串口驱动 * port:要挂起的串口端口 *返回值:成功返回0;否则返回错误码 */ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) 3.1.7. uart_resume_port /*功能:uart_resume_port用于恢复某一已挂起的串口 *参数: * drv:要恢复的串口端口所属的串口驱动 * port:要恢复的串口端口 *返回值:成功返回0;否则返回错误码 */ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) 3.1.8. uart_get_baud_rate /*功能:uart_get_baud_rate通过解码termios结构体来获取指定串口的波特率 *参数: * port:要获取波特率的串口端口 * termios:当前期望的termios配置(包括串口波特率) * old:以前的termios配置,可以为NULL * min:可以接受的最小波特率 * max:可以接受的最大波特率 * 返回值:串口波特率 */ unsigned int uart_get_baund_rate(struct uart_port *port, struct ktermios *termios, struct ktermios *old,unsigned int min, unsigned int max) 3.1.9. uart_get_divisor /*功能:uart_get_divisor 用于计算某一波特率的串口时钟分频数(串口波特率除数) *参数: * port:要计算分频数的串口端口 * baud:期望的波特率 *返回值:串口时钟分频数 */ unsigned int uart_get_divisor(struct uart_port *port, unsigned int baund) 3.1.10. uart_update_timeout /*功能:uart_update_timeout用于更新(设置)串口FIFO超出时间 *参数: * port:要更新超时间的串口端口 * cfalg:termios结构体的cflag值 * baud:串口的波特率 */ void uart_update_timeout(struct uart_port *port,unsigned int cflag, unsigned int baud) 3.1.11. uart_insert_char /*功能:uart_insert_char用于向uart层插入一个字符 *参数: * port:要写信息的串口端口 * status:RX buffer状态 * overrun:在status中的overrun bit掩码 * ch:需要插入的字符 * flag:插入字符的flag:TTY_BREAK,TTY_PSRIYY, TTY_FRAME */ void uart_insert_char(struct uart_port *port, unsigned int status, unsigned int overrun,unsigned int ch, unsigned int flag) 3.1.12. uart_console_write /*功能:uart_console_write用于向串口端口写一控制台信息 *参数: * port:要写信息的串口端口 * s:要写的信息 * count:信息的大小 * putchar:用于向串口端口写字符的函数,该函数有两个参数:串口端口和要写的字符 */ Void uart_console_write(struct uart_port *port,const char *s, unsigned int count,viod(*putchar)(struct uart_port*, int)) 4. 模块使用说明 4.1. 串口编程 4.1.1. 串口控制函数 属性 说明
tcgetatrr 取属性(termios结构)
tcsetarr 设置属性(termios结构)
cfgetispeed 得到输入速度
cfsetispeed 得到输出速度
cfstospeed 设置输出速度
tcdrain 等待所有输出都被传输
tcflow 挂起传输或接收
tcflush 刷请未决输出和/或输入
tcsendbreak 送BREAK字符
tcgetpgrp 得到前台进程组ID
Tcsetpgrp 设置前台进程组ID
4.1.2. 串口配置流程
(1) 保持原先串口配置,使用tegetatrr(fd, &oldtio);
struct termious newtio, oldtio; tegetattr(fd, &oldtio);(2) 激活选项有CLOCAL和CREAD,用于本地连接和接收使用
newtio.cflag |= CLOCAL|CREAD;(3) 设置波特率
newtio.c_cflag = B115200;(4) 设置数据位,需使用掩码设置
newtio.c_cflag &= ~CSIZE; Newtio.c_cflag |= CS8;