你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。
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管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号
手机版
快速回复
返回顶部
返回列表
#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;
}
}