很多时候,用户发送具体消息的时候,也需要发送一个消息长度。比如在网卡中断中接收到了一包数据,发送消息给外面任务的时候,也需要告诉外面的任务消息的长度是多少。使用之前的queue模块做需要一点小技巧,但是使用queue_size模块做的话,显的很直接,直接可以发送出去。
带有消息长度的消息机制有一种很有用的用法。假设有一个串口接收中断来了,接收数据的话可以采用信号量+fifo 或者queue+块内存分配去做,但是这两种多多少少有些缺点。信号量+fifo的方式处理的话,fifo内部是关了cpu全局中断去操作的,如果数据量比较大的话,这个会严重影响实时性。queue +block内存区分配的话,如果中断接收每次来的数据都不同的话,会严重浪费内存。
有没有经济实用的不关中断,又节约内存的方式操作呢。答案是肯定的。当串口接收中断来的时候,用户需要自己维护一个简单的fifo缓冲区,但是这个缓冲区不需要关中断,写到头了重新回到头去写就好。当接收到数据填好缓冲区的时候,把缓冲区的这次数据起始地址以及数据长度通过raw_queue_size_end_post 发送出去。同时外面有一个任务调用raw_queue_size_receive接收数据。具体的示例如下:
staticRAW_U32 recv_temp_buffer[12]; (1)
staticRAW_U32 *uart_p; (2)
staticRAW_U32 uart_data_length (3)
void uart_int_recevie_handle(void)
{
RAW_U32 length_temp;
RAW_U32 uart_recv_length;
RAW_U8 *p_temp;
uart_recv_length = 读串口数据的长度
length_temp = uart_recv_length;
if (raw_queue_size_full_check()) {
/*do something thing and return*/
return;
}
/*if isr receive data is faster than task data process, just ignore the data*/
if (uart_data_length >= (12 * 4)) {
/*do something thing and return*/
return;
}
if ((uart_p + (uart_recv_length >> 2))> = (recv_temp_buffer + 12)) {
uart_p = recv_temp_buffer;
}
p_temp = (RAW_U8 *)uart_p;
while (length_temp--) {
*p_temp++ = 串口数据;
}
queue_size_end_post(queue_size, uart_p, uart_recv_length);
if(uart_recv_length & 3) {
uart_data_length += 4u - (uart_recv_length& 3u)+ uart_recv_length;
uart_p = uart_p + (uart_recv_length>> 2) + 1;
}
else {
uart_p = uart_p + (uart_recv_length>> 2)
uart_data_length += uart_recv_length;
}
}
RAW_U32process_buffer[10];
void task_uart_receive()
{
RAW_U8 receive_size;
void * msg_ptr;
while (1) {
raw_queue_size_receive(&q_size,RAW_WAIT_FOREVER, &msg_ptr,
&receive_size);
raw_memcpy(process_buffer,msg_ptr, receive_size);
RAW_CPU_DISABLE();
if(receive_size & 3) {
uart_data_length = uart_data_length - (4u- (receive_size & 3u) + receive_size);
}
else {
uart_data_length -= receive_size;
}
RAW_CPU_ENABLE();
/*processsreceived data, processed time must be smaller than interrupt frequecy*/
}
}
(1)处用户自己维护了一个缓冲区,缓冲区的数据长度是48个字节。
(2)处代码的uart_p用来记录缓冲区的写位置。
(3)处代码维护一个长度,如果长度超过了缓冲区的长度就丢弃数据,返回,保证不会去覆盖缓冲区的数据。
以上的操作避免了临界区的缓冲区的操作,又节省了内存开销。而且数据执行效率上比起fifo也要高,因为少了一次copy动作。
本帖最后由 jorya_txj 于 2014-1-5 20:18 编辑