0%

USART使用ringbuffer实现无阻塞的读写

USART 使用 ringbuffer 实现无阻塞的读写

在使用串口的使用中,由于速率比较低,因此数据的收发都比较占用资源。尤其是数据的输入,因为在程序的执行过程中无法预知到底何时才有数据过来,采用中断的方式去实现接收也有弊端,当需要解析帧协议时需要不断的去判断是否有足够一帧的数据,而且在发送过程中也无法实现无阻塞。从而浪费了大量的 CPU 资源。这里采用一种 ringbuffer 的方式去实现无阻塞的收发,发送数据时只需要数据写入 buffer 即可,不需要等待完全发送完毕才退出。接收数据时,可以先判断缓存中是否有足够的数据,再去取出缓存的数据。而且在没有数据的时候,即使调用 getchar,也不会阻塞。因此使用起来比较方便。代码的实现比较简单,很容易就能移植到其他的平台。

usart 初始化与接口函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include "includes.h"

static tRingBuffer RingBufferUART1TX;
static tRingBuffer RingBufferUART1RX;
unsigned int IrqCntUart1;

static int usart_getchar(void)
{
return RingBufferGet(&RingBufferUART1RX);
}

static void usart_putchar(uint8_t ch)
{
RingBufferPut(&RingBufferUART1TX, ch, 1);
}

static void usart_putstring(uint8_t *str)
{
while (*str != 0)
{
usart_putchar(*str);

str++;
}
}

/* usart 接收缓存中剩余数据 */
int usart_available(void)
{
return RingBufferFillLevel(&RingBufferUART1RX);
}

static int lastChar = -1;

int get_char(void) // 读取一个 Byte, 如果缓存为空, 返回 -1
{
if (lastChar < 0)
{
return usart_getchar();
}
else
{
int c = lastChar;

lastChar = -1;

return c;
}
}

void usart_flush(void)
{
while (RingBufferFillLevel(&RingBufferUART1TX) != 0);
}

void print(const char *fmt, ...)
{
char buf[128];

va_list vlist;
va_start(vlist, fmt);

vsnprintf(buf, sizeof(buf) - 1, fmt, vlist);

usart_putstring((unsigned char *)buf);

va_end(vlist);
}

static void usart_tx_Interrupt_en(void)
{
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
}

static void uart_buffer_init(void)
{
RingBufferInit(&RingBufferUART1TX, &usart_tx_Interrupt_en);
RingBufferInit(&RingBufferUART1RX, 0L);
}

static void usart_nvic_init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/* 串口初始化 */
void debug_usart_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/* -------------------------- 端口配置 -------------------------- */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);

USART_InitStructure.USART_BaudRate = 256000;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);

/* 使能接收中断 */
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
uart_buffer_init();
usart_nvic_init();
}
/* USART 中断处理函数 */
void USART1_IRQHandler(void)
{
int sr = USART1->SR;
IrqCntUart1++;
if (sr & USART_FLAG_TXE)
{
tRingBuffer *rb = &RingBufferUART1TX;
if (rb->Read != rb->Write)
{
USART1->DR = rb->Buffer[rb->Read];
if (rb->Read + 1 == RingBufferSize(rb))
{
rb->Read = 0;
}
else
{
rb->Read++;
}
}
else
{
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
__ASM volatile("nop");
__ASM volatile("nop");
}
}
if (sr & USART_FLAG_RXNE)
{
tRingBuffer *rb = &RingBufferUART1RX;
unsigned char c = USART1->DR;
if (RingBufferFillLevel(rb) + 1 == RingBufferSize(rb))
{
rb->Overrun++; return;
}
rb->Buffer[rb->Write] = c;
if (rb->Write + 1 == RingBufferSize(rb))
{
rb->Write = 0;
}
else
{
rb->Write++;
}
}
}

与平台无关的 ringbuffer 文件

ringbuffer.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef RINGBUFFER_H_
#define RINGBUFFER_H_

typedef struct
{
volatile int Read, Write, Overrun;
unsigned char Buffer[128];
void (*CallBack)(void);
}tRingBuffer;

void RingBufferInit(tRingBuffer *rb, void (*callback)(void));
int RingBufferSize(tRingBuffer *rb);
int RingBufferFillLevel(tRingBuffer *rb);
void RingBufferPut(tRingBuffer *rb, unsigned char c, int block);
void RingBufferPutBlock(tRingBuffer *rb, unsigned char *data, int dataLen, int block);
int RingBufferGet(tRingBuffer *rb);
int RingBufferPeek(tRingBuffer *rb);

#endif /* RINGBUFFER_H_ */

ringbuffer.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include "includes.h"

void RingBufferInit(tRingBuffer *rb, void (*callback)(void))
{
rb->Read = 0;
rb->Write = 0;
rb->Overrun = 0;
rb->CallBack = callback;
}

int RingBufferSize(tRingBuffer *rb)
{
return sizeof(rb->Buffer);
}

int RingBufferFillLevel(tRingBuffer *rb)
{
return (rb->Write - rb->Read + RingBufferSize(rb)) % RingBufferSize(rb);
}

void RingBufferPut(tRingBuffer *rb, unsigned char c, int block)
{
if (block)
{
while (RingBufferFillLevel(rb) + 1 == RingBufferSize(rb));
}
else
{
if (RingBufferFillLevel(rb) + 1 == RingBufferSize(rb))
{
rb->Overrun++;

return;
}
}

rb->Buffer[rb->Write] = c;

if (rb->Write + 1 == RingBufferSize(rb))
{
rb->Write = 0;
}
else
{
rb->Write++;
}

if (rb->CallBack)
{
rb->CallBack();
}
}

void RingBufferPutBlock(tRingBuffer *rb, unsigned char *data, int dataLen, int block)
{
if (block)
{
while (RingBufferFillLevel(rb) + dataLen >= RingBufferSize(rb));
}
else
{
if (RingBufferFillLevel(rb) + dataLen >= RingBufferSize(rb))
{
rb->Overrun += dataLen;

if (rb->CallBack)
{
rb->CallBack();
}

return;
}
}

int free1 = RingBufferSize(rb) - rb->Write;

if (dataLen <= free1)
{
memcpy(rb->Buffer + rb->Write, data, dataLen);

if (rb->Write + dataLen == RingBufferSize(rb))
{
rb->Write = 0;
}
else
{
rb->Write += dataLen;
}
}
else
{
memcpy(rb->Buffer + rb->Write, data, free1);

int len2 = dataLen - free1;

memcpy(rb->Buffer, data + free1, len2);

rb->Write = len2;
}

if (rb->CallBack)
{
rb->CallBack();
}
}

int RingBufferGet(tRingBuffer *rb)
{
if (rb->Read == rb->Write)
{
return -1;
}
else
{
unsigned char c = rb->Buffer[rb->Read];

if (rb->Read + 1 == RingBufferSize(rb))
{
rb->Read = 0;
}
else
{
rb->Read++;
}

return c;
}
}

int RingBufferPeek(tRingBuffer *rb)
{
if (rb->Read == rb->Write)
{
return -1;
}
else
{
int c = rb->Buffer[rb->Read];

return c;
}
}

使用 :

1、调用 debug_usart_init() 初始化串口和收发 ringbuffer

2、调用 get_char() 函数读取一个字节的数据, 该函数不会阻塞, 如果返回 -1 表示缓存中没有数据

3、调用 print() 发送数据, 该函数不会等到发送完成才返回, 只是将数据写入 buffer, 后面会自己去开启发

送中断函数完成发送。如果确实需要等到发送完成, 可以调用 usart_flush 函数。
————————————————
原文链接:https://blog.csdn.net/zhou0842/article/details/53574199