主循环里面写环形队列,中断里面读取,如果主循环写数据的时候,发生了中断,写的过程被打断,那会出现数据错误吗,我的答案是不会,看看环形队列的结构
#define DEFINE_QUEUE_TYPE(NAME, TYPE, SIZE) \
typedef struct { \
TYPE data[SIZE]; \
int front; \
int rear; \
int size; \
int max_size; \
} NAME##_queue; \
\
void NAME##_queue_init(NAME##_queue *queue) { \
queue->front = 0; \
queue->rear = -1; \
queue->size = 0; \
queue->max_size = SIZE; \
} \
\
bool NAME##_queue_is_empty(NAME##_queue *queue) { \
return queue->size == 0; \
} \
\
bool NAME##_queue_is_full(NAME##_queue *queue) { \
return queue->size == queue->max_size; \
} \
\
bool NAME##_queue_push(NAME##_queue *queue, TYPE value) { \
if (NAME##_queue_is_full(queue)) { \
return false; \
} \
queue->rear = (queue->rear + 1) % queue->max_size; \
queue->data[queue->rear] = value; \
queue->size++; \
return true; \
} \
bool NAME##_queue_pop(NAME##_queue *queue) { \
if (NAME##_queue_is_empty(queue)) { \
return false; \
} \
queue->front = (queue->front + 1) % queue->max_size; \
queue->size--; \
return true; \
} \
bool NAME##_queue_front(NAME##_queue *queue, TYPE *value) { \
if (NAME##_queue_is_empty(queue)) { \
return false; \
} \
*value = queue->data[queue->front]; \
return true; \
}
这是一个环形队列的模板,结构体里面包含数据缓存,读指针和写指针。
在主循环里面写的时候用push操作,push里面首先会检查队列是否满,如果满了,则不会进行写入操作。
while (1)
{
RUN_BY_LIMIT_BLOCK(2,
for (int i = 0; i < PUSH_TIMES; i++){
u16_queue_push(&test_queue, TEST_NUMBER1);
u16_queue_push(&test_queue, TEST_NUMBER2);
}
)
}
在中断里面读取的时候用front和pop操作,front里面会判断队列是否为空,不为空才会进行读取。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if (htim->Instance == TIM10) {
RUN_BY_LIMIT_BLOCK(1000,
SEGGER_RTT_printf(0, "tim10 interrupt!\n")
)
uint16_t tmp;
while (u16_queue_front(&test_queue, &tmp) == true) {
u16_queue_pop(&test_queue);
if (tmp != TEST_NUMBER1 && tmp != TEST_NUMBER2) {
SEGGER_RTT_printf(0, "[%d]***************queue error! data: 0x%04X\n",HAL_GetTick(), tmp);
}else {
SEGGER_RTT_printf(0, "[%d]queue ok, data: 0x%04X!\n", HAL_GetTick(), tmp);
}
}
}
}
如何在写的时候突然中断来了,写入还没完成怎么办,比如写入的是一个结构体或者u16的数据。如果这时候中断来了,主循环的现场会保存,中断里面判断空的时候,用的是size还是上一次的,因为size的变化要等到push完成后才会改变,所以读取不会发生错误,等中断结束再回到主循环,继续写入操作。
同样写入到 时候会判断是否为满,中断前不是满的,中断读取后仍然不是满的,所以写入也不会出错。
经过2天的实测,主循环2ms写入1024个数据,中断1ms读取一次,暂时还没有发现错误。
源码在此,不需要积分