本帖最后由 mack13013 于 2016-7-25 20:37 编辑
谁用STM32F4的串口DMA接收了?
有没有寄存器版本的代码?
我用串口DMA,DMA总是不能触发,每次接收数据都是0。
空闲中断倒是好用,也能实现不定长、非换行数据接收,只是放着DMA这个个东西在那里浪费者总不是个事。
自己的代码贴出来吧,哪位大侠帮忙看看什么问题.
[mw_shl_code=c,true]
int main(void)
{
Stm32_Clock_Init(336,8,2,7); //设置时钟,168Mhz
delay_init(168); //初始化延时函数
Board_Init();
DMA_Config(DMA1_Stream5, 4, (u32)USART2 ->DR, (u32)USART_RX_BUF, USART_BUFF_LEN, 0);
usart2_init(42,9600); //串口初始化为9600
for(;;)
{
}
}
[/mw_shl_code]
[mw_shl_code=c,true]
//串口2中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[USART_BUFF_LEN]; //接收缓冲,最大USART_BUFF_LEN个字节.
u8 USART_TX_BUF[USART_BUFF_LEN]; //发送缓冲,最大USART_BUFF_LEN个字节.
u32 unRcvCnt = 0;
u8 ucRcvLen = 0;
void USART2_IRQHandler(void)
{
volatile u8 ucRcv;
u8 ucSndCnt = 0;
if(USART2 ->SR & (1 << 4))//线路空闲
{
USART_RX_BUF[ucRcvLen] = USART2->DR; //这里读取一下,防止硬件检测未读取
ucRcvLen++;
unRcvCnt++;
// if(DMA1 ->HISR & (1 << 27))
// {
// DMA1 ->HIFCR |= (1 << 27);
// }
// unRcvLen = DMA1_Stream5 ->NDTR;
// if(16 == USART_BUFF_LEN - DMA1_Stream5 ->NDTR)//接收到了正常的16字节数据
// {
// }
// memcpy(USART_TX_BUF, &unRcvCnt, sizeof(u32));
// USART_TX_BUF[sizeof(u32)] = 0;
memcpy(USART_TX_BUF, USART_RX_BUF, 16);
for(ucSndCnt = 0; ucSndCnt < DEFAULT_RCVSND_LEN; ucSndCnt++)
{
while((USART2->SR&0X40)==0)
{
;//等待发送空闲
}
USART2 ->DR = USART_TX_BUF[ucSndCnt];
}
USART2 ->SR &= ~(1 << 4);//清除空闲中断状态
DMA_Enable(DMA1_Stream5);
ucRcvLen = 0;
}
}
//初始化IO 串口2
//pclk2
CLK2时钟频率(Mhz)
//bound:波特率
void usart2_init(u32 pclk2, u32 bound)
{
float temp;
u16 mantissa;
u16 fraction;
temp=(float)(pclk2 * 1000000) / (bound * 16);//得到USARTDIV@OVER8=0
mantissa = temp; //得到整数部分
fraction = (temp - mantissa) * 16; //得到小数部分@OVER8=0
mantissa <<= 4;
mantissa += fraction;
//RCC->AHB1ENR |= 1 << 3; //使能PORTD口时钟
RCC->APB1ENR |= 1 << 17; //使能串口2时钟
GPIO_Set(GPIOD, PIN5 | PIN6, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_SPEED_50M, GPIO_PUPD_PU);//PD5、PD6复用功能,推挽上拉输出
GPIO_AF_Set(GPIOD, 5, 7); //PD5,AF7
GPIO_AF_Set(GPIOD, 6, 7); //PD5,AF7
//波特率设置
USART2 ->BRR = mantissa; //波特率设置
USART2 ->CR1 &= ~(1 << 15); //设置OVER8=0
USART2 ->CR1 |= 1 << 3; //串口发送使能
//使能接收中断
USART2 ->CR1 |= 1 << 2; //串口接收使能
// USART2 ->CR1 |= 1 << 5; //接收缓冲区非空中断使能
USART2 ->CR1 |= 1 << 4; //使能空闲中断
USART2 ->CR3 |= 1 << 6; //串口2使能DMA接收
//USART2 ->CR3 |= 1 << 7; //串口2使能DMA发送
MY_NVIC_Init(3, 3, USART2_IRQn, 2);//组2,最低优先级
USART2->CR1 |= 1 << 13; //串口使能
}
[/mw_shl_code]
[mw_shl_code=c,true]
//DMAx的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_Streamx
MA数据流,DMA1_Stream0~7/DMA2_Stream0~7
//chx
MA通道选择,范围:0~7
//par:外设地址
//mar:存储器地址
//ndtr:数据传输量
//, u8 ucStreamTo:数据传输方向 0:外设到存储器 1: 存储器到外设 2:存储器到存储器
void DMA_Config(DMA_Stream_TypeDef *DMA_Streamx, u8 chx, u32 par, u32 mar, u16 ndtr, u8 ucStreamTo)
{
DMA_TypeDef *DMAx;
u8 streamx;
if((u32)DMA_Streamx > (u32)DMA2)//得到当前stream是属于DMA2还是DMA1
{
DMAx = DMA2;
RCC ->AHB1ENR |= 1 << 22;//DMA2时钟使能
}
else
{
DMAx = DMA1;
RCC->AHB1ENR |= 1 << 21;//DMA1时钟使能
}
while(DMA_Streamx ->CR & 0X01)
{
;//等待DMA可配置
}
streamx = (((u32)DMA_Streamx-(u32)DMAx) - 0X10) / 0X18; //得到stream通道号
if(streamx>=6)
{
DMAx ->HIFCR|=0X3D << (6*(streamx-6)+16); //清空之前该stream上的所有中断标志
}
else if(streamx >= 4)
{
DMAx ->HIFCR|=0X3D << (6*(streamx-4)); //清空之前该stream上的所有中断标志
}
else if(streamx >= 2)
{
DMAx ->LIFCR|=0X3D << (6*(streamx-2)+16);//清空之前该stream上的所有中断标志
}
else
{
DMAx ->LIFCR |= 0X3D << (6*streamx); //清空之前该stream上的所有中断标志
}
DMA_Streamx ->
AR = par; //DMA外设地址
DMA_Streamx ->M0AR = mar; //DMA 存储器0地址
DMA_Streamx ->NDTR = ndtr; //长度
DMA_Streamx ->CR = 0; //先全部复位CR寄存器值
DMA_Streamx ->CR |= (ucStreamTo & 3) << 6; //传输方向
DMA_Streamx ->CR |= 0 << 8; //非循环模式(即使用普通模式)
DMA_Streamx ->CR |= 0 << 9; //外设非增量模式
DMA_Streamx ->CR |= 1 << 10; //存储器增量模式
DMA_Streamx ->CR |= 0 << 11; //外设数据长度:8位
DMA_Streamx ->CR |= 0 << 13; //存储器数据长度:8位
DMA_Streamx ->CR |= 1 << 16; //中等优先级
DMA_Streamx ->CR |= 0 << 21; //外设突发单次传输
DMA_Streamx ->CR |= 0 << 23; //存储器突发单次传输
DMA_Streamx ->CR |= (u32)chx << 25; //通道选择
//DMA_Streamx ->FCR=0X21; //FIFO控制寄存器
DMA_Enable(DMA1_Stream5);
}
//开启一次DMA传输
//DMA_Streamx
MA数据流,DMA1_Stream0~7/DMA2_Stream0~7
//ndtr:数据传输量
void DMA_Enable(DMA_Stream_TypeDef *DMA_Streamx)
{
DMA_Streamx ->CR &= ~(1<<0); //关闭DMA传输
while(DMA_Streamx ->CR & 0X1)
{
; //确保DMA可以被设置
}
DMA_Streamx ->NDTR = DEFAULT_RCVSND_LEN; //DMA 数据长度
DMA_Streamx ->CR |= 1 << 0; //开启DMA传输
}
[/mw_shl_code]
仅在第一次接收之后能获取正常的长度,之后的获取都是初始值。
跟踪库函数版本,也是获取NDTR数据。不知道是不是可用。
不知道是不是需要volatile修饰才行。
看了一下定义,NDTR是加了__IO修饰符的。 这下无解了,看样子确实是硬件设置初始值的。
看下CR或者SR哪里还能设置吧
使能TCIE、HTIE中断,失败。
难不成STM32F407有缺陷? 参考手册上也说是会复位,如果复位的话,如何判断接收数据长度??
看来串口接收只能抛弃DMA了
一周热门 更多>