本帖最后由 654705188 于 2015-7-16 09:24 编辑
#ifndef _RDCOM_H_
#define _RDCOM_H_
#include "driver_about.h"
//////////////////////////////////////////////////////////////////////
#define RDCOMDEBUG 0
#define RDCOM_MODE RDCOM_DMA//USART收发数据的方式-查询、中断、DMA
#define RDCOMUSART USART1 //串口号
#define RDCOM_RCC_APBnPeriphClockCmd() RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE)//打开串口时钟
//配置IO口前别忘了开启IO时钟
#define RDCOMRX_PORT GPIOA
#define RDCOMRX_PIN GPIO_Pin_10//RX
#define RDCOMTX_PORT GPIOA
#define RDCOMTX_PIN GPIO_Pin_9//TX
////////////////////中断方式下需要配置////////////////////////////////
#define RDCOMUSART_IRQ USART1_IRQn //串口接收中断
#define RDCOMUSART_IRQHandler USART1_IRQHandler //串口接收中断服务
////////////////////DMA方式下需要配置////////////////////////////////
#define RDCOMPerph_Addr (u32)(&(USART1->DR)) //串口发送寄存器作为目的地址
#define RDCOM_RCC_AHBPeriphClockCmd() RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE)//DMA时钟
#define RDCOMDMAn_Channeln_Send DMA1_Channel4//DMA通道TX选择
#define RDCOMDMAn_IT_TC_Send DMA1_IT_TC4//传输完成中断
#define RDCOMDMAn_IT_TE_Send DMA1_IT_TE4//传输错误中断
#define RDCOMDMAn_IT_GL_Send DMA1_IT_GL4//全部中断
#define RDCOMDMAn_Chn_IRQn_Send DMA1_Channel4_IRQn
#define RDCOMUSART_DMAHandler_Send DMA1_Channel4_IRQHandler//DMA中断服务
#define RDCOMDMAn_Channeln_Recv DMA1_Channel5//DMA通道RX选择
#define RDCOMDMAn_FLAG_GL_Recv DMA1_FLAG_GL5//DMA传输的所有标志
#define RDCOMDMAn_IT_TC_Recv DMA1_IT_TC5//传输完成中断
#define RDCOMDMAn_IT_TE_Recv DMA1_IT_TE5//传输错误中断
#define RDCOMDMAn_IT_GL_Recv DMA1_IT_GL5//全部中断
#define RDCOMDMAn_Chn_IRQn_Recv DMA1_Channel5_IRQn
#define RDCOMUSART_DMAHandler_Recv DMA1_Channel5_IRQHandler//DMA中断服务
/////////////////// 以下不需要修改////////////////////////////////////
#define RDCOM_NORMAL 0 //USART收发数据的方式的选项
#define RDCOM_INT 1
#define RDCOM_DMA 2
s8 RDCOMUsartInit(u32 baudrate);//串口初始化,输入波特率,只需要调用此函数即可完成初始化
//////////////////查询方式下:mode=RDCOM_NORMAL/////////////////
#if(RDCOM_MODE==RDCOM_NORMAL)
u8 RDCOMnormal_Send(u8 *data,u8 len);
u8 RDCOMnormal_Receive(u8 *data,u16 timeout_ms);
u8 RDCOMnormal_Receive_Char(u8 *data,char ch,u16 timeout_ms);
u8 RDCOMnormal_Receive_Len(u8 *data,u8 len,u16 timeout_ms);
#endif
//////////////////中断方式下:mode=RDCOM_INT/////////////////
#if(RDCOM_MODE==RDCOM_INT)
void RDCOMUSART_IRQHandler(void);//中断接收服务
#endif
//////////////////DMA方式下 :mode=RDCOM_DMA/////////////////
#if(RDCOM_MODE==RDCOM_DMA)
u8 RDCOMDMA_Send(u8 *Send_Data,u8 len);//通过DMA发送数据
void RDCOMUSART_DMAHandler(void);//USART的DMA发送完成或错误中断服务
#endif
////////////////////////////////////////////////////////////////////////
extern s8 RDCOM_Send(u8 *sdata,u8 len,OS_TICK timeout);
extern s8 RDCOM_Recv(u8 *rdata,u8 *len,OS_TICK timeout);
extern s8 RDCOM_SendRecv(u8 *send_data,u8 send_len,u8 *recv_data,u8 *recv_len,OS_TICK timeout);//有延时的发送和接收数据
#endif
#include "rdcom.h"
#if(RDCOM_MODE==RDCOM_DMA)
static CPU_TS ts=0; //存放发送消息时的时间戳OS_TS_GET()
static OS_ERR err; //返回的错误信息
OS_SEM RDCOMSend_Sem;
OS_SEM RDCOMRecv_Sem;
#endif
void RDCOMGPIO_Config(void)//串口IO口配置
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = RDCOMRX_PIN;//
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;//2M
GPIO_Init(RDCOMRX_PORT,&GPIO_InitStructure);//
GPIO_InitStructure.GPIO_Pin = RDCOMTX_PIN;//
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;//2M
GPIO_Init(RDCOMTX_PORT, &GPIO_InitStructure);//
}
void RDCOMUSART_Config(u32 baudrate)//串口初始化
{
USART_InitTypeDef USART_InitStructure;
RDCOM_RCC_APBnPeriphClockCmd();
USART_StructInit(&USART_InitStructure);//将结构体设置为缺省状态,9600bps,8数据位,1停止位,不校验,硬件流控制失能
USART_InitStructure.USART_BaudRate =baudrate;//波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//一帧数据的宽度设置为8bits
USART_InitStructure.USART_StopBits = USART_StopBits_1;//在帧结尾传输1个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//奇偶失能模式,无奇偶校验
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//发送/接收使能
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制失能
USART_Init(RDCOMUSART, &USART_InitStructure);//设置串口
#if(RDCOM_MODE==RDCOM_INT)
USART_ITConfig(RDCOMUSART, USART_IT_RXNE, ENABLE);//打开接收中断
#endif
USART_Cmd(RDCOMUSART, ENABLE);//打开串口
USART_GetFlagStatus(RDCOMUSART, USART_FLAG_TC);
//发送数据前先清除标志位,否则第1字节数据会丢失
}
///////////////////查询方式下///////////////////////////////////
#if(RDCOM_MODE==RDCOM_NORMAL)
u8 RDCOMnormal_Send(u8 *data,u8 len)
{
u8 i=0;
for(i=0;i<len;i++)
{
USART_SendData(RDCOMUSART, data);//发送数据
while(USART_GetFlagStatus(RDCOMUSART, USART_FLAG_TC) == RESET);//等待数据发送完毕
}
return i;
}
u8 RDCOMnormal_Receive(u8 *data,u16 timeout_ms)
{
u32 timeout=timeout_ms*740,timeout_count=0;
u8 i=0;
while(timeout_count<timeout)//等待时间设置
{
if (USART_GetFlagStatus(RDCOMUSART, USART_FLAG_RXNE) != RESET) //判断接收标志;查询方式的USART接收
{
data[i++]=USART_ReceiveData(RDCOMUSART);
timeout_count=0;
}
else
{
timeout_count++;
}
}
return i;
}
u8 RDCOMnormal_Receive_Char(u8 *data,char ch,u16 timeout_ms)//ms
{
u32 timeout=timeout_ms*740,timeout_count=0;
u8 i=0;
while(timeout_count<timeout)//等待时间设置600000=800ms
{
if (USART_GetFlagStatus(RDCOMUSART, USART_FLAG_RXNE) != RESET) //判断接收标志;查询方式的USART接收
{
data[i++]=USART_ReceiveData(RDCOMUSART);
timeout_count=0;
if(data[i-1]==ch)
break;
}
else
{
timeout_count++;
}
}
return i;
}
u8 RDCOMnormal_Receive_Len(u8 *data,u8 len,u16 timeout_ms)
{
u32 timeout=timeout_ms*740,timeout_count=0;
u8 i=0;
while(timeout_count<timeout)//等待时间设置
{
if (USART_GetFlagStatus(RDCOMUSART, USART_FLAG_RXNE) != RESET) //判断接收标志;查询方式的USART接收
{
data[i++]=USART_ReceiveData(RDCOMUSART);
timeout_count=0;
if(i>=len)
break;
}
else
{
timeout_count++;
}
}
return i;
}
#endif
///////////////////中断方式下////////////////////////////////////////////////////////////////////////
#if(RDCOM_MODE==RDCOM_INT)
void RDCOMUSART_IRQHandler(void)//中断方式的USART接收
{
if(USART_GetITStatus(RDCOMUSART, USART_IT_RXNE) != RESET) //判断发生接收中断
{//USART_ClearITPendingBit(RDCOMUSART, USART_IT_RXNE); //清除中断标志,读接收到的数据时自动清除
//USART_SendData(RDCOMUSART, USART_ReceiveData(RDCOMUSART));//发送数据
//while(USART_GetFlagStatus(RDCOMUSART, USART_FLAG_TC) == RESET);//等待数据发送完毕
}
}
void RDCOMNVIC_Config(void)//配置中断
{
NVIC_InitTypeDef NVIC_InitStructure;
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//选择中断分组1
NVIC_InitStructure.NVIC_IRQChannel = RDCOMUSART_IRQ;//选择串口中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢占式中断优先级设置为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//响应式中断优先级设置为3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能中断
NVIC_Init(&NVIC_InitStructure);
}
#endif
///////////////////DMA方式下////////////////////////////////////////////////////////////////////////
#if(RDCOM_MODE==RDCOM_DMA)
u8 RDCOMDMA_Send(u8 *send_data,u8 len)
{
DMA_InitTypeDef DMA_InitStructure;
//if(RDCOM_DMASend_Finish!=1)//发送未完成
//return 0;
//RDCOM_DMASend_Finish=0;//DMA发送完成的标志,1为发送完成
USART_GetFlagStatus(RDCOMUSART,USART_FLAG_ORE);//清溢出标志USART_FLAG_NE,USART_FLAG_FE,USART_FLAG_PE
USART_ReceiveData(RDCOMUSART);//清缓存
RDCOM_RCC_AHBPeriphClockCmd();
DMA_DeInit(RDCOMDMAn_Channeln_Send);//复位DMA-TX通道
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)RDCOMPerph_Addr;//外设地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)send_data;//内存地址,自己开辟的数组
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外设作为数据传输的目的地
DMA_InitStructure.DMA_BufferSize = len;//传输的数据长度,单位在下边设置
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//设置DMA外设递增模式禁止
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //设置DMA内存递增模式使能
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设字长为字节
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//内存地址
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 设置传输模式-单次
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//设置DMA优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//内存到内存禁止
DMA_Init(RDCOMDMAn_Channeln_Send, &DMA_InitStructure);//配置完成后,启动DMA通道
USART_DMACmd(RDCOMUSART,USART_DMAReq_Tx,ENABLE);//使能USART的发送DMA请求
DMA_Cmd(RDCOMDMAn_Channeln_Send, ENABLE);
DMA_ITConfig(RDCOMDMAn_Channeln_Send, DMA_IT_TC, ENABLE); //DMA传输完成
return len;
}
void RDCOMDMANVIC_Config_Send(void)//配置中断
{
NVIC_InitTypeDef NVIC_InitStructure;
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//选择中断分组1
NVIC_InitStructure.NVIC_IRQChannel = RDCOMDMAn_Chn_IRQn_Send;//选择DMA中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢占式中断优先级设置为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;//响应式中断优先级设置为3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能中断
NVIC_Init(&NVIC_InitStructure);
}
void RDCOMUSART_DMAHandler_Send(void)//USART的DMA发送完成或错误中断
{
OSIntEnter();
if(DMA_GetITStatus(RDCOMDMAn_IT_TC_Send) != RESET) //判断发生DMA发送完成中断
{
//RDCOM_DMASend_Finish=1;//DMA发送完成的标志,1为发送完成
OSSemPost(&RDCOMSend_Sem,OS_OPT_POST_1,&err);//发送完成信号
DMA_ClearITPendingBit(RDCOMDMAn_IT_GL_Send); //清除全部中断标志
}
OSIntExit();
}
u8 RDCOMDMA_Recv(u8 *recv_data,u8 len)
{
DMA_InitTypeDef DMA_InitStructure;
//if(RDCOM_DMARecv_Finish!=1)//接收未完成
//return 0;
//RDCOM_DMARecv_Finish=0;//DMA接收完成的标志,1为接收完成
USART_GetFlagStatus(RDCOMUSART,USART_FLAG_ORE);//清溢出标志USART_FLAG_NE,USART_FLAG_FE,USART_FLAG_PE
USART_ReceiveData(RDCOMUSART);//清缓存
RDCOM_RCC_AHBPeriphClockCmd();
DMA_DeInit(RDCOMDMAn_Channeln_Recv);//复位DMA-RX通道
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)RDCOMPerph_Addr;//外设地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)recv_data;//内存地址,自己开辟的数组
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//外设作为数据传输的数据源
DMA_InitStructure.DMA_BufferSize = len;//传输的数据长度,单位在下边设置
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//设置DMA外设递增模式禁止
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //设置DMA内存递增模式使能
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设字长为字节
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//内存地址
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 设置传输模式-单次
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//设置DMA优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//内存到内存禁止
DMA_Init(RDCOMDMAn_Channeln_Recv, &DMA_InitStructure);//配置完成后,启动DMA通道
USART_DMACmd(RDCOMUSART,USART_DMAReq_Rx,ENABLE);//使能USART的接收DMA请求
DMA_Cmd(RDCOMDMAn_Channeln_Recv, ENABLE);
DMA_ITConfig(RDCOMDMAn_Channeln_Recv, DMA_IT_TC, ENABLE); //DMA传输完成
return len;
}
void RDCOMDMANVIC_Config_Recv(void)//配置中断
{
NVIC_InitTypeDef NVIC_InitStructure;
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//选择中断分组1
NVIC_InitStructure.NVIC_IRQChannel = RDCOMDMAn_Chn_IRQn_Recv;//选择DMA中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢占式中断优先级设置为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//响应式中断优先级设置为2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能中断
NVIC_Init(&NVIC_InitStructure);
}
void RDCOMUSART_DMAHandler_Recv(void)//USART的DMA接收完成或错误中断
{
OSIntEnter();
USART_DMACmd(RDCOMUSART,USART_DMAReq_Rx,DISABLE);//禁能USART的接收DMA请求
if(DMA_GetITStatus(RDCOMDMAn_IT_TC_Recv) != RESET) //判断发生DMA接收完成中断
{
//RDCOM_DMARecv_Finish=1;//DMA接收完成的标志,1为接收完成
OSSemPost(&RDCOMRecv_Sem,OS_OPT_POST_1,&err);//发送完成信号
DMA_ClearITPendingBit(RDCOMDMAn_IT_GL_Recv); //清除全部中断标志
}
OSIntExit();
}
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////
s8 RDCOMUsartInit(u32 baudrate)
{
RDCOMUSART_Config(baudrate);//串口初始化,与第二句顺序互换是避免复位后发送一个FF
RDCOMGPIO_Config();//串口IO口配置
#if(RDCOM_MODE==RDCOM_INT)
RDCOMNVIC_Config();//配置中断
#endif
#if(RDCOM_MODE==RDCOM_DMA)
RDCOMDMANVIC_Config_Send();
RDCOMDMANVIC_Config_Recv();
OSSemCreate(&RDCOMSend_Sem,(char *)"RDCOMSend Sem", 0, &err);
OSSemCreate(&RDCOMRecv_Sem,(char *)"RDCOMRecv Sem", 0, &err);
#endif
return ERR_NO;
}
/**************************************************************************************
**********************以下为RDCOM设置处理函数******************************************
***************************************************************************************/
s8 RDCOM_Send(u8 *sdata,u8 len,OS_TICK timeout)//OS_CFG_TICK_RATE_HZ
{
if(len>0)//有发送数据
{
OSSemSet(&RDCOMSend_Sem,0,&err);//清发送信号量
RDCOMDMA_Send((u8 *)sdata,len);//开始发送
OSSemPend(&RDCOMSend_Sem,timeout,OS_OPT_PEND_BLOCKING,&ts,&err);//信号量等待
USART_DMACmd(RDCOMUSART,USART_DMAReq_Tx,DISABLE);//禁能USART的发送DMA请求
if(err!=OS_ERR_NONE) return ERR_ERROR;//发送数据时出错
}
return ERR_NO;
}
s8 RDCOM_Recv(u8 *rdata,u8 *len,OS_TICK timeout)
{
s8 re=0;
memset(rdata,0,DATAPKG_MAXLEN);
OSSemSet (&RDCOMRecv_Sem,0,&err);//清接收信号量
RDCOMDMA_Recv(rdata,DATAPKG_XORMINLEN);//开始接收
OSSemPend(&RDCOMRecv_Sem,timeout,OS_OPT_PEND_BLOCKING,&ts,&err);//信号量等待
if(err!=OS_ERR_NONE)
{
return ERR_ERROR;
}
re=Check_Data_Pkghead(rdata);
if(re==ERR_NO)//数据头正确
{
RDCOMDMA_Recv(DATARECV(rdata)->DATA,DATARECV_DLEN(rdata)+DATAPKG_MINLEN-DATAPKG_XORMINLEN);//开始接收
OSSemPend(&RDCOMRecv_Sem,timeout,OS_OPT_PEND_BLOCKING,&ts,&err);//信号量等待
if(err==OS_ERR_NONE)
{
*len=DATARECV_DLEN(rdata)+DATAPKG_MINLEN;
return ERR_NO;
}
if(err==OS_ERR_TIMEOUT)//第二次接收超时
{
*len=DATAPKG_XORMINLEN;
return ERR_NO;
}
}
//头错误
{
USART_DMACmd(RDCOMUSART,USART_DMAReq_Rx,DISABLE);//禁能USART的接收DMA请求
return re;
}
}
s8 RDCOM_SendRecv(u8 *send_data,u8 send_len,u8 *recv_data,u8 *recv_len,OS_TICK timeout)//有延时的发送和接收数据
{
s8 re=0;
memset(recv_data,0,DATAPKG_MAXLEN);
OSSemSet (&RDCOMRecv_Sem,0,&err);//清接收信号量
if(send_len>0)//有发送数据
{
OSSemSet(&RDCOMSend_Sem,0,&err);//清发送信号量
RDCOMDMA_Send((u8 *)send_data,send_len);//开始发送
OSSemPend(&RDCOMSend_Sem,timeout,OS_OPT_PEND_BLOCKING,0,&err);//信号量等待
if(err!=OS_ERR_NONE) return ERR_ERROR;
}
RDCOMDMA_Recv(recv_data,DATAPKG_MAXLEN);//开始接收
OSSemPend(&RDCOMRecv_Sem,timeout,OS_OPT_PEND_BLOCKING,&ts,&err);//信号量等待100ms
if(err==OS_ERR_NONE)
{
*recv_len=DATARECV_DLEN(recv_data)+DATAPKG_MINLEN;
return ERR_NO;
}
if(err==OS_ERR_TIMEOUT)//第二次接收超时
{
*recv_len=DATAPKG_XORMINLEN;
return ERR_NO;
}
//错误
{
USART_DMACmd(RDCOMUSART,USART_DMAReq_Rx,DISABLE);//禁能USART的接收DMA请求
return re;
}
}
这是商业项目中的一个模块,恕我不便发出。
其实如果去掉有关 OS的几句,然后直接复制到.h 和.c文件就可以编译的。
只有楼主自己能懂吧。。。
还不如说下实现的机制
其实并不乱啊,都是由三个宏控制的
#define RDCOMDEBUG 0//是否使能串口debug调试
#define RDCOM_MODE RDCOM_DMA//USART收发数据的方式-查询、中断、DMA
#define RDCOMUSART USART1 //串口号
静下心来,就会明白的。
一周热门 更多>