中断方式的数据接收2
Echo实验
回忆之前的实验因为数据处理的过程可以瞬间完成所以可以把数据处理的操作放在中断服务函数中执行
但是数据处理要是时间过长就将数据缓存处理
当使用中断方式接收数据的时候 一般有两种方式 数据处理的时间较短可放在中断服务函数内处理(就地处理) 第二种就是数据处理时间较长需要缓存数据来延时处理
就地处理
当RXNE每次由0变为1就表示有一个数据传入 (一个字符的传入) 第一个字符为H 存入数组a[0] 接着接收剩余的字符 直到满足条件 数组a的倒数第二个位存放的是字符\r 最后一个位置存放的是字符\n 就发送数据 同时清空数组
但是发送数据的操作太占时间了 无法瞬间处理 所以需要延时处理数据
在发送数据的时候因为时间过长 无法做到瞬间处理 如果这时候有数据传输进来就会造成数据的丢失 所以不能使用就地处理的方式
队列简介
队列的工作原理
队列c语言的实现
注意Tail最开始的位置指向就是数组的第一个位置
其中出队的操作 返回值为errorstatus 传入参数为记录出队的数据
当队列为空的时候 出队错误 返回ERROR 只有队列不为空才可以正常出队
头文件主要是声明结构体和函数的 源文件主要是实现函数的原型的
queue.h
#ifndef _QUEUE_H_
#define _QUEUE_H_
#include "stm32f10x.h"
typedef struct
{
uint8_t Data[100];
uint16_t Tail;//队尾
}Queue_HandleTypeDef;
void Queue_Init(Queue_HandleTypeDef *hQueue); //队列的初始化
void Queue_Enqueue(Queue_HandleTypeDef *hQueue,uint8_t Element);//进队操作
ErrorStatus Queue_Dequeue(Queue_HandleTypeDef *hQueue, uint8_t *pElement);//出队操作
#endif //防止头文件被重复引用
queue.c
#include "queue.h"
void Queue_Init(Queue_HandleTypeDef *hQueue)
{
hQueue ->Tail = 0;//初始化指针指向数组的第一个位置
}
void Queue_Enqueue(Queue_HandleTypeDef *hQueue,uint8_t Element)
{
hQueue ->Data[hQueue->Tail ++] = Element; //进队操作
}
ErrorStatus Queue_Dequeue( Queue_HandleTypeDef *hQueue ,uint8_t *pElement) //把一个元素移出队列
{
uint16_t i;
if(hQueue ->Tail == 0) return ERROR; //队列空操作无效
*pElement = hQueue ->Data[0]; //输出的元素用变量pElement接收
for(i=0;i<hQueue->Tail-1;i++)
{
hQueue->Data[i] = hQueue->Data[i+1];//把第一个元素从队列中拿走 就将队列中的剩余元素全都向前移一个位 右边的变为左边的
}
hQueue->Tail--; //指针右移一个位
return SUCCESS;
}
延迟处理
在触发中断后 在中断服务函数中把数据存放到缓冲区 然后在进程函数中把数据从缓冲区取出 进行处理
为了防止在进程函数中出队的过程被中断函数打断
进程函数
static void USART_Echo_Proc(void)
{
uint8_t c;
USART_ITConfig(USART1, USART_IT_RXNE, DISABLE); //为了防止在进程函数中出队的过程被中断函数打断
ErrorStatus error = Queue_Dequeue(&hQueue, &c);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
if(error == SUCCESS)
{
a[cursor++] = c;
if(cursor>2 && a[cursor-2] == '\r'&& a[cursor - 1] == '\n') // 收到新行
{
// 发送出去
a[cursor] = 0;
USART1_SendString((const char *)a);
cursor=0;
}
}
}