简要
使用DMA发送和接收不定长USART1串口数据
.H文件
#ifndef __DMA_USART1_H
#define __DMA_USART1_H
#include "stm32f10x.h"
void GPIO_Usart1_Init(void);
void USART_NVIC_Config(void);
void USART_DMA_RX(void);
void USART_DMA_TX(void);
#endif
.c文件
声名两个数组
uint8_t RX_Buffer[128];
uint8_t TX_Buffer[128];
配置GPIOA_Pin9和GPIOA_Pin10
void GPIO_Usart1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能APB2总线的GPPIOA端口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //使能APB2总线的USART1外设
/*配置GPIOA_Pin_11引脚*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; //使用浮空输入模式
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; //PIN_11为RX数据接受引脚
//GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //可定义可不定义都不影响
GPIO_Init(GPIOA,&GPIO_InitStruct); //将赋值的结构体乘员写入寄存器
/*配置GPIOA_Pin_12引脚*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; //使用复用推挽输出模式复用USART
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; //PIN_12为TX数据发送引脚
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //可定义可不定义都不影响
GPIO_Init(GPIOA,&GPIO_InitStruct);
/*配置USART1模式等*/
USART_InitStruct.USART_BaudRate = 9600; //波特率设置为9600
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //不启用硬件控制接收端接收到的数据处理不过来时,就向发送端发送不再接收的信号,发送端接收到这个信号之后就会停止发送,直到收到可以继续发送的信号再继续发送。因此流控本身是可以控制数据传输的进度,进而防止数据丢失。
USART_InitStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; //接收和发送都打开
USART_InitStruct.USART_Parity = USART_Parity_No; //不启用奇偶校验
USART_InitStruct.USART_StopBits = USART_StopBits_1; //一个停止位
USART_InitStruct.USART_WordLength = USART_WordLength_8b ; //数据长度为8位
USART_Init(USART1,&USART_InitStruct);
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); //当检测到总线空闲时,该位被硬件置位。
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //接收缓冲区非空中断使能
USART_ITConfig(USART1,USART_IT_TC,ENABLE); //当包含有数据的一帧发送完成后,并且TXE=1时,由硬件将该位置’1’。
/*配置USART1接收中断*/
USART_NVIC_Config();
USART_Cmd(USART1, ENABLE);
}
配置接收DMA
/*配置USART1—DMA接收*/
void USART_DMA_RX(void)
{
DMA_InitTypeDef DMA_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); //开启DMA1时钟
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设接口数据宽度8位 //发送数据的地址
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址增量模式不自增
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //存储器数据宽度为8位
DMA_InitStruct.DMA_PeripheralBaseAddr = USART1_BASE+0x04; //stm32f10x.h 1327行
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)RX_Buffer; //指定一块内存用来储存DMA接收到的数据
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址增量模式不自增
DMA_InitStruct.DMA_Priority = DMA_Priority_VeryHigh ; //优先级非常高
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; //外设到内存
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; //普通不循环模式{DMA_BufferSize = 8;|normal:上位机发送1234567890接收:12345678//Circular:上位机发送1234567890接收:90345678|}
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //禁止内存到内存传输
DMA_InitStruct.DMA_BufferSize = 128;
DMA_Init(DMA1_Channel5,&DMA_InitStruct);
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //开启DMA接收串口数据
DMA_Cmd(DMA1_Channel5,ENABLE);
}
配置发送DMA
/*配置USART1—DMA发送*/
void USART_DMA_TX(void)
{
DMA_InitTypeDef DMA_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设接口数据宽度8位 //发送数据的地址
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址增量模式不自增
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //存储器数据宽度为8位
DMA_InitStruct.DMA_PeripheralBaseAddr = (USART1_BASE+0x04); //stm32f10x.h 1327行
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)TX_Buffer; //指定一块内存用来DMA发送数据
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址增量模式不自增
DMA_InitStruct.DMA_Priority = DMA_Priority_High ; //优先级非常高
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST; //内存到外设
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; //普通不循环模式{DMA_BufferSize = 8;|normal:上位机发送1234567890接收:12345678//Circular:上位机发送1234567890接收:90345678|}
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //禁止内存到内存传输
DMA_InitStruct.DMA_BufferSize = 128;
DMA_Init(DMA1_Channel4,&DMA_InitStruct);
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
DMA_Cmd(DMA1_Channel4,DISABLE);
}
配置USART1串口NVIC
/*配置USART1中断*/
void USART_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //一位抢占优先级,3为响应优先级
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; //选择USART1通道(stm32f10x.h)
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //使能USART1通道
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级(可取0或1)
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; //响应优先级(可取0到7)
NVIC_Init(&NVIC_InitStruct);
}
USART1中断服务函数
/*USART1中断服务程序*/
void USART1_IRQHandler(void)
{
int i,l;
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) //监测到总线空闲
{
DMA_Cmd(DMA1_Channel5,DISABLE); //关闭接收DMA防止数据覆盖(可用双缓存解决,设置两个缓存数组)
l=128-DMA_GetCurrDataCounter(DMA1_Channel5);
for(i=0;i<l;i++)//将接收到的内容复制给发送数组
{
TX_Buffer[i]=RX_Buffer[i];
}
DMA_Cmd(DMA1_Channel4,DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel4,l);
DMA_Cmd(DMA1_Channel4,ENABLE);
USART_ReceiveData(USART1);
USART_ClearITPendingBit(USART1,USART_IT_IDLE); //清除IDLE标志必须先将SR和DR寄存器的内容读取(手册)
DMA_SetCurrDataCounter(DMA1_Channel5,128); //每次接收完需重新设定CNTDR寄存器,否者接收不到数据
}
if(USART_GetITStatus(USART1, USART_IT_TC) != RESET) //发送完成
{
DMA_Cmd(DMA1_Channel4,DISABLE);
USART_ClearITPendingBit(USART1,USART_IT_TC);
}
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //触发接收,开启接收DMA
{
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
DMA_Cmd(DMA1_Channel5,ENABLE);
}
}
man.c
#include "stm32f10x.h"
#include "./DMA_USART/DMA_USART1.h"
extern uint8_t RX_Buffer[128];
extern uint8_t TX_Buffer[128];
int i;
int main (void)
{
GPIO_Usart1_Init();
USART_DMA_RX();
USART_DMA_TX();
while(1)
{}
}