你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。
chrome
firefox
safari
ie8及以上
ST
意法半导体官网
STM32
中文官网
ST
全球论坛
登录/注册
首页
技术问答
话题
资源
创客秀
视频
标签
积分商城
每日签到
大家使用过STM32的DMA功能吗?感觉怎么样。
[复制链接]
lhb292
提问时间:2015-1-10 15:37 /
问答
是否解决:
单选投票
, 共有 252 人参与投票
查看投票参与人
投票已经结束
1. 经常使用,和RTOS配合,既方便有高效。
29.37%
(74)
2. 只用过一两次。
30.56%
(77)
3. 以前尝试使用过,但是没有成功,或者没有感觉到明显的优点。
3.57%
(9)
4. 只听说有这个功能,没有真正使用过。
25.00%
(63)
5. stm32有这个功能?
1.59%
(4)
6. DMA是干什么用的啊?
9.92%
(25)
您所在的用户组没有投票权限
赞
0
收藏
3
评论
97
分享
发布时间:2015-1-10 15:37
举报
请先
登录
后回复
97个回答
lhb292
最优答案
回答时间:2015-1-23 09:02:14
a1024a.1 32b0c
给大家发个DMA串口收发的例子吧,来抛砖引玉。
#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
赞
0
评论
回复
lhb292
最优答案
回答时间:2015-1-23 09:03:40
a1024a.1 32b0c
#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[i]);//发送数据
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();
}
赞
0
评论
回复
lhb292
最优答案
回答时间:2015-1-23 09:04:17
a1024a.1 32b0c
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;
}
}
赞
0
评论
回复
show明
回答时间:2015-1-11 07:47:06
a1024a.1 32b0c
跟ADC搭配着使用,感觉挺好用的。
赞
0
评论
回复
wamcncn
回答时间:2015-1-11 15:42:43
a1024a.1 32b0c
还是上学的时候学过的概念,没应用过
赞
0
评论
回复
拼命三郎
回答时间:2015-1-12 09:00:35
a1024a.1 32b0c
还不错,不用不行
赞
0
评论
回复
火蒂树
回答时间:2015-1-12 13:22:29
a1024a.1 32b0c
用得好的话, 省时省力
赞
0
评论
回复
qzwx741
回答时间:2015-1-12 14:23:02
a1024a.1 32b0c
一只再用,感觉杠杠的
赞
0
评论
回复
dajin123
回答时间:2015-1-12 14:26:24
a1024a.1 32b0c
adc用着很好
赞
0
评论
回复
zhangdaijin
回答时间:2015-1-14 18:48:37
a1024a.1 32b0c
通信的时候用的着
赞
0
评论
回复
wjandsq
回答时间:2015-1-19 16:30:59
a1024a.1 32b0c
一直在用,但没有RTOS
赞
0
评论
回复
chendiand
回答时间:2015-1-19 20:08:44
a1024a.1 32b0c
还没用到
赞
0
评论
回复
我是酱油哥
回答时间:2015-1-20 08:36:15
a1024a.1 32b0c
我一直都没用过 啊
赞
0
评论
回复
wyxy163@126.com
回答时间:2015-1-20 10:19:17
a1024a.1 32b0c
提示:
作者被禁止或删除 内容自动屏蔽
赞
0
评论
回复
1
2
3
4
5
6
7
/ 7 页
下一页
所属标签
相似问题
关于
意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
微信公众号
手机版
快速回复
返回顶部
返回列表
#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
#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[i]);//发送数据
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();
}
{
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;
}
}