my_data_queue.h
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
#ifndef __ESP_DATA_QUEUE_H_
#define __ESP_DATA_QUEUE_H_
#include "stm32f10x.h"
#include <string.h>
#include <stdio.h>
//缓冲队列的个数需要为2的幂
#define QUEUE_NODE_NUM (2) //缓冲队列的大小(有多少个缓冲区)
#define QUEUE_NODE_DATA_LEN (2*1024 ) //单个接收缓冲区大小
//数据主体
typedef struct
{
uint8_t *head; //缓冲区头指针
uint16_t len; //接收到的数据长度
} QUEUE_DATA_TYPE ;
//队列结构
typedef struct {
int size; /* 缓冲区大小 */
int read; /* 读指针 */
int write; /* 写指针 */
int read_using; /*正在读取的缓冲区指针*/
int write_using; /*正在写入的缓冲区指针*/
QUEUE_DATA_TYPE *elems[QUEUE_NODE_NUM]; /* 缓冲区地址 */
} QueueBuffer;
extern QueueBuffer rx_queue;
QUEUE_DATA_TYPE* cbWrite(QueueBuffer *cb);
QUEUE_DATA_TYPE* cbRead(QueueBuffer *cb);
void cbReadFinish(QueueBuffer *cb);
void cbWriteFinish(QueueBuffer *cb);
int cbIsFull(QueueBuffer *cb) ;
int cbIsEmpty(QueueBuffer *cb) ;
void RX_Queue_Init(void);
#endif
my_data_queue.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
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
171
#include "my_data_queue.h"
//实例化节点数据类型
QUEUE_DATA_TYPE node_data[QUEUE_NODE_NUM];
//实例化队列类型
QueueBuffer rx_queue;
//队列缓冲区的内存池
__align(4) uint8_t node_buff[QUEUE_NODE_NUM][QUEUE_NODE_DATA_LEN] ;
/*环形缓冲队列*/
/**
* @brief 初始化缓冲队列
* @param cb:缓冲队列结构体
* @param size: 缓冲队列的元素个数
* @note 初始化时还需要给cb->elems指针赋值
*/
void cbInit(QueueBuffer *cb, int size)
{
cb->size = size; /* maximum number of elements */
cb->read = 0; /* index of oldest element */
cb->write = 0; /* index at which to write new element */
// cb->elems = (uint8_t *)calloc(cb->size, sizeof(uint8_t)); //elems 要额外初始化
}
/**
* @brief 判断缓冲队列是(1)否(0)已满
* @param cb:缓冲队列结构体
*/
int cbIsFull(QueueBuffer *cb)
{
return cb->write == (cb->read ^ cb->size); /* This inverts the most significant bit of read before comparison */
}
/**
* @brief 判断缓冲队列是(1)否(0)全空
* @param cb:缓冲队列结构体
*/
int cbIsEmpty(QueueBuffer *cb)
{
return cb->write == cb->read;
}
/**
* @brief 对缓冲队列的指针加1
* @param cb:缓冲队列结构体
* @param p:要加1的指针
* @return 返回加1的结果
*/
int cbIncr(QueueBuffer *cb, int p)
{
return (p + 1)&(2*cb->size-1); /* read and write pointers incrementation is done modulo 2*size */
}
/**
* @brief 获取可写入的缓冲区指针
* @param cb:缓冲队列结构体
* @return 可进行写入的缓冲区指针
* @note 得到指针后可进入写入操作,但写指针不会立即加1,
写完数据时,应调用cbWriteFinish对写指针加1
*/
QUEUE_DATA_TYPE* cbWrite(QueueBuffer *cb)
{
if (cbIsFull(cb)) /* full, overwrite moves read pointer */
{
return NULL;
}
else
{
//当wriet和write_using相等时,表示上一个缓冲区已写入完毕,需要对写指针加1
if(cb->write == cb->write_using)
{
cb->write_using = cbIncr(cb, cb->write); //未满,则增加1
}
}
return cb->elems[cb->write_using&(cb->size-1)];
}
/**
* @brief 数据写入完毕,更新写指针到缓冲结构体
* @param cb:缓冲队列结构体
*/
void cbWriteFinish(QueueBuffer *cb)
{
cb->write = cb->write_using;
}
/**
* @brief 获取可读取的缓冲区指针
* @param cb:缓冲队列结构体
* @return 可进行读取的缓冲区指针
* @note 得到指针后可进入读取操作,但读指针不会立即加1,
读取完数据时,应调用cbReadFinish对读指针加1
*/
QUEUE_DATA_TYPE* cbRead(QueueBuffer *cb)
{
if(cbIsEmpty(cb))
return NULL;
//当read和read_using相等时,表示上一个缓冲区已读取完毕(即已调用cbReadFinish),
//需要对写指针加1
if(cb->read == cb->read_using)
cb->read_using = cbIncr(cb, cb->read);
return cb->elems[cb->read_using&(cb->size-1)];
}
/**
* @brief 数据读取完毕,更新读指针到缓冲结构体
* @param cb:缓冲队列结构体
*/
void cbReadFinish(QueueBuffer *cb)
{
//重置当前读完的数据节点的长度
cb->elems[cb->read_using&(cb->size-1)]->len = 0;
cb->read = cb->read_using;
}
//队列的指针指向的缓冲区全部销毁
void camera_queue_free(void)
{
uint32_t i = 0;
for(i = 0; i < QUEUE_NODE_NUM; i ++)
{
if(node_data[i].head != NULL)
{
//若是动态申请的空间才要free
// free(node_data[i].head);
node_data[i].head = NULL;
}
}
return;
}
/**
* @brief 缓冲队列初始化,分配内存,使用缓冲队列时,
* @param 无
* @retval 无
*/
void RX_Queue_Init(void)
{
uint32_t i = 0;
memset(node_data, 0, sizeof(node_data));
/*初始化缓冲队列*/
cbInit(&rx_queue,QUEUE_NODE_NUM);
for(i = 0; i < QUEUE_NODE_NUM; i ++)
{
node_data[i].head = node_buff[i];
/*初始化队列缓冲指针,指向实际的内存*/
rx_queue.elems[i] = &node_data[i];
memset(node_data[i].head, 0, QUEUE_NODE_DATA_LEN);
}
}
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
/**
* @brief 串口中断服务函数
* @param 无
* @retval 无
*/
void DEBUG_USART_IRQHandler(void)
{
uint8_t ucCh;
QUEUE_DATA_TYPE *data_p;
if (USART_GetITStatus(DEBUG_USARTx, USART_IT_RXNE) != RESET)
{
ucCh = USART_ReceiveData(DEBUG_USARTx);
/*获取写缓冲区指针,准备写入新数据*/
data_p = cbWrite(&rx_queue);
if (data_p != NULL) //若缓冲队列未满,开始传输
{
//往缓冲区写入数据,如使用串口接收、dma写入等方式
*(data_p->head + data_p->len) = ucCh;
if (++data_p->len >= QUEUE_NODE_DATA_LEN)
{
cbWriteFinish(&rx_queue);
}
}
else
return;
}
//数据帧接收完毕
if (USART_GetITStatus(DEBUG_USARTx, USART_IT_IDLE) == SET)
{
/*写入缓冲区完毕*/
cbWriteFinish(&rx_queue);
//由软件序列清除中断标志位(先读USART_SR,然后读USART_DR)
ucCh = USART_ReceiveData(DEBUG_USARTx);
}
}
my_process_data.h
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
#ifndef __PROCESS_DATA_H
#define __PROCESS_DATA_H
#include "stm32f10x.h"
#include "my_data_queue.h"
#include "my_usart.h"
/*********************数据****************************/
#define HEAD_BYTE0 0x5A //接收头低字节
#define HEAD_BYTE1 0xA5 //接收头高字节
#define CMD_READ 0x83 //数据下发命令
typedef struct {
uint8_t state;//状态
uint8_t start_up;//状态
uint8_t stop_up;//状态
uint16_t strength;//强度
uint8_t mod;//模式
} Channel;
#define CHANNEL_A 0X10 //通道1
#define CHANNEL_B 0X11 //通道2
#define ADDR_SWITCH 0x10 //开关
#define ADDR_STRENGTH 0x11 //强度
#define ADDR_MOD 0x12 //模式
#define BUTTON_LEN 0x01 //按键自动下发参数长度
#define PARAMETER_LEN 0x03 //参数检测数据长度
/**
* @brief 串口数据处理
* @param 通道
* @retval 无
*/
void Process_Usart_Data(Channel *ch);
#endif
my_process_data.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
143
144
145
146
147
148
149
150
151
152
153
154
155
/**
******************************************************************************
* @file my_process_data.c
* @author
* @version V1.0
* @date
* @brief 串口数据处理程序
******************************************************************************
* @attention
*
* 定义 帧头 数据长度 指令 数据
* 数据长度 5A A5 该项右侧全部数据的长度加和 82或83 N
*
* 举例:
* 82指令:变量地址(word)+ 写入的变量数据(word)
* 向地址(0x1000)写数据1:5A A5 05 82 10 00 00 01
* 向地址(0x1000 0x1001)写数据1,2:5A A5 07 82 10 00 00 01 00 02
* 83指令:变量地址(word)+ 地址数量+变量数据(word)
* 地址(0x1000)发来的数据1:5A A5 06 83 10 00 01 00 01
* 地址(0x1000 0x1001)发来的数据1,2:5A A5 08 83 10 00 02 00 01 00 02
*
*
******************************************************************************
*/
#include "my_process_data.h"
/**
* @brief 通道设置
* @param ch 通道 cmd 串口数据
* @retval 无
*/
static void Set_Channel(Channel *ch, uint8_t *cmd)
{
switch (cmd[5])
{
case ADDR_SWITCH:
switch (cmd[6])
{
case BUTTON_LEN:
ch->state = cmd[8];
break;
case PARAMETER_LEN:
ch->state = cmd[8];
ch->strength = (((cmd[9] << 8) & 0xFF00) | (cmd[10] & 0xFF));
ch->mod = cmd[12]; //模式
break;
default:
break;
}
break;
case ADDR_MOD:
ch->mod = cmd[8];
break;
case ADDR_STRENGTH:
ch->strength = (((cmd[7] << 8) & 0xFF00) | (cmd[8] & 0xFF));
break;
default:
break;
}
}
/**
* @brief 通道分配
* @param ch 通道 cmd 串口数据
* @retval 无
*/
static void Sel_Channel(Channel *ch, uint8_t *cmd)
{
if (cmd[4] == CHANNEL_A)
{
Set_Channel(&ch[0], cmd);
}
else if (cmd[4] == CHANNEL_B)
{
Set_Channel(&ch[1], cmd);
}
}
/**
* @brief 串口数据处理
* @param 通道
* @retval 无
*/
static void Process_Data(Channel *ch, uint8_t *array, uint16_t data_len)
{
uint16_t i = 0;
uint16_t len = 0;
if (data_len > 8)
{
if ((array[0] == HEAD_BYTE0) && (array[1] == HEAD_BYTE1) && (array[3] == CMD_READ) && ((array[6] * 2 + 4) == array[2]) && (data_len >= (array[2] + 3)))
{
len = array[2] + 3;
for (i = 7; i < (data_len - 1); i++)
{
if ((array[i] == HEAD_BYTE0) && (array[i + 1] == HEAD_BYTE1))
{
len = i;
break;
}
}
if (len >= (array[2] + 3))
{
Sel_Channel(ch, array);
}
if (data_len > len)
{
memmove(array,array+len,data_len - len);
Process_Data(ch, array, data_len - len);
}
}
else
{
if (data_len > 9)
{
for (i = 1; i < (data_len - 1); i++)
{
if ((array[i] == HEAD_BYTE0) && (array[i + 1] == HEAD_BYTE1))
{
len = i;
break;
}
}
if (len > 0)
{
memmove(array,array+len,data_len - len);
Process_Data(ch, array, data_len - len);
}
}
}
}
}
/**
* @brief 串口数据处理
* @param 通道
* @retval 无
*/
void Process_Usart_Data(Channel *ch)
{
QUEUE_DATA_TYPE *rx_data;
uint8_t *array;
/*从缓冲区读取数据,进行处理,*/
rx_data = cbRead(&rx_queue);
if (rx_data != NULL) //缓冲队列非空
{
array = (uint8_t *)rx_data->head;
if (rx_data->len > 8)
{
if ((array[0] == HEAD_BYTE0) && (array[1] == HEAD_BYTE1) && (array[3] == CMD_READ) && ((array[6] * 2 + 4) == array[2]))
{
Process_Data(ch, array, rx_data->len);
}
}
//使用完数据必须调用cbReadFinish更新读指针
cbReadFinish(&rx_queue);
}
}
main.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
#include "stm32f10x.h"
#include "my_gpio.h"
#include "my_usart.h"
#include "my_data_queue.h"
#include "my_process_data.h"
Channel ch[2];
int main(void)
{
/* LED 端口初始化 */
LED_GPIO_Config();
Key_GPIO_Config();
/* 初始化USART 配置模式为 9600 8-N-1 */
USART_Config();
/*初始化接收数据队列*/
RX_Queue_Init();
while (1)
{
Process_Usart_Data(ch);
if (Key_Scan(KEY1_GPIO_PORT, KEY1_GPIO_PIN) == KEY_ON)
{
/*LED1反转*/
LED1_TOGGLE;
}
if (Key_Scan(KEY2_GPIO_PORT, KEY2_GPIO_PIN) == KEY_ON)
{
LED2_TOGGLE;
}
if(ch[0].state==1&&ch[0].start_up==0)
{
ch[0].stop_up=0;
ch[0].start_up=1;
LED1(ON);
}
if(ch[0].state==2&&ch[0].stop_up==0)
{
ch[0].stop_up=1;
ch[0].start_up=0;
LED1(OFF);
}
if(ch[1].state==1&&ch[1].start_up==0)
{
ch[1].stop_up=0;
ch[1].start_up=1;
LED2(ON);
}
if(ch[1].state==2&&ch[1].stop_up==0)
{
ch[1].stop_up=1;
ch[1].start_up=0;
LED2(OFF);
}
}
}
5A A5 06 83 10 10 01 00 01
会看到LED1亮5A A5 06 83 10 10 01 00 02
会看到LED1灭5A A5 06 83 11 10 01 00 01
会看到LED2亮5A A5 06 83 11 10 01 00 02
会看到LED2灭5A A5 06 83 10 10 01 00 01 5A A5 06 83 11 10 01 00 01
会看到LED1亮LED2亮,这个验证了如果上位机两帧发送过快,系统仍然可以正常处理数据,而不是出现个别帧不处理