第一章 第七节 嵌入式串口fifo的设计实现 -闫刚

串口是通信中最常用的通信方式,大家可能写串口的驱动,能写几十种方法, 查询方式,中断方式, DMA方式,定时器方式。可能也其中几种方式的组合形式,经典的用法是: 发送用查询方式, 接收用中断方式。 下面我说下这几种方式的优点和确定吧。

1. 查询方式

1) 优点: 可靠性很高,也许要考虑下个数据包覆盖上一个数据包的问题,小数据量,在10个字节以内,可以这样考虑, 很简单,很方便,很可靠,我也这样使用多年

2)缺陷: 数据量大的时候,程序阻塞的时间特别长,影响其他比较重要的外设的处理

 

2. 中断方式

1)优点:  中断方式 , 不占用系统资源,但是如果数据量大,会频繁中断cpu, 会其他高优先的数据处理造成影响

2) 缺陷: 没有DMA,不占用资源的好处, 如果没有串口队列的实现,必须通过标志位判断上一个包数据是否发送完成,在把新的数据覆盖到串口的缓冲区

 

3. DMA方式

1)优点:  不占用系统资源,减少CPU对中断的响应

2)缺陷: 如何不建立数据包的队列,还是会出现,需要等待阻塞的问题

 

实现代码,下载链接: 通过git工具进行克隆代码

直接放大招

git clone https://github.com/yangang123/stm32_driver

第一章 第七节 嵌入式串口fifo的设计实现 -闫刚_第1张图片

第一章 第七节 嵌入式串口fifo的设计实现 -闫刚_第2张图片

 

模拟Linux操作系统和nuttx,rtthread操作系统的串口驱动实现:

发送和接收,都采用fifo的模式。

1. 发送函数

 

void write(int fd, uint8_t *buf, uint16_t len)

write函数是1个非阻塞的api, 直接写入数据到串口驱动的缓冲区,驱动层有数据后会自动从串口通过中断的方式发送数据出去

2. 接收函数

 

void read(int fd, uint8_t *buf, uint16_t len)

read是1个非阻塞的api, 可以从底层缓冲区去读取数。

3. ioctrl机制

 

int ioctl(int fd, int cmd, uint32_t *arg)

ioctrl机制,我可以通过发送命令到这个api.获取可读的缓冲区数据的长度

 

典型应用:

#include "serial.h"
#include "uart.h"

/*
 fd : 0 是串口1
 fd : 2 是串口3

*/

void uart_test()
{   
	/* 初始化串口 */
    uart_init1(115200);
	uart_init3(9600);
	
	uint8_t buf[10];

	for (uint8_t i =0; i < 10; i++) {
		buf[i] = i;
	}
    
	/* 发送数据 */
	write(0,  buf,  sizeof(buf));

	while(1) {
 		
		/* 获取数据的长度 */
		uint32_t data_cnt = 0;   
		if( ioctl(0, AVAILABLE_READ_LEN_CMD, &data_cnt) < 0) {
			continue;
		}
        /* 获取数据  */
		uint8_t buf[10];
		if (data_cnt > 0)  {
			read((int)0, &buf[0], data_cnt);
		}
	}
}

 

 

渗入理解,串口TXE标志位:

 

 

第一章 第七节 嵌入式串口fifo的设计实现 -闫刚_第3张图片

串口发送的核心中断是TXE,  移位寄存器为空,就会触发中断,我们可以使用这个中断作为发送数据的标志,外部使能中断,中断调用需要发送的数据,发送数据的时候从buffer中读取数据, 最后1个数据发送完成,先进行关闭TXE中断。

 

void uart_common(struct uart_dev_s *dev)

{

    /* recevied data */

    if (USART_GetITStatus(dev->uart, USART_IT_RXNE)!= RESET) {

        uint8_t val = (uint8_t)dev->uart->DR;

        uart_rx_ringbuffer_push_from_usart(dev, &val);

    }

    

    /* transmit data */

    if(USART_GetITStatus(dev->uart, USART_IT_TXE) != RESET) {

        if(uart_tx_ringbuffer_pop_to_usart(dev) == 0) {

            USART_ITConfig(dev->uart, USART_IT_TXE, DISABLE);

        }

    }

}

 

你可能感兴趣的:(第一章 第七节 嵌入式串口fifo的设计实现 -闫刚)