中级会员
 
- 积分
- 204
- 金钱
- 204
- 注册时间
- 2019-9-20
- 在线时间
- 103 小时
|
5金钱
大家好!具体问题是这样的:
STM32F103C8T6的串口2的DMA收发,采用串口空闲中断,测试程序功能是将串口助手发送的数据发送回来:
1、第一次用串口助手发送数据,进入串口接收中断,获得的数据长度rs485_receive_len=0;
2、第二次发送,进中断,能收到数据,但是数据长度和数据都不对,比实际的大1。
3、从第三次发送开始开始,通讯就都正常了:
主要程序如下:
#define TX_BUF_SIZE 100
#define RX_BUF_SIZE 100
uint8_t Rs485_TX_Buf[TX_BUF_SIZE];
uint8_t Rs485_RX_Buf[RX_BUF_SIZE];
uint8_t rs485_receive_flag=0; //串口接收数据标志位
uint8_t rs485_receive_len=0; //串口接收数据长度
uint8_t dma_send_en=0; //可以发送标志位
//u16 DMA1_MEM_LEN;//保存DMA每次数据传送的长度
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_CHx MA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量
static void DMA1_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr,uint8_t dir)
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输
DMA_DeInit(DMA_CHx); //将DMA的通道1寄存器重设为缺省值
//DMA1_MEM_LEN=cndtr;
DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设基地址
DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址
if(dir==0)
{ DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; } //数据传输方向,从内存读取发送到外设
if(dir==1)
{ DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; } //数据传输方向,从外设读取发送到内存
DMA_InitStructure.DMA_BufferSize = cndtr; //DMA通道的DMA缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为8位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
DMA_Init(DMA_CHx, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel7_IRQn; //使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //先占优先级2级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 6; //从优先级2级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
DMA_ITConfig(DMA1_Channel7, DMA_IT_TC , ENABLE);
}
void RS485_DMA_Send(uint8_t *send_buff,uint8_t length)
{
unsigned int counter = 0;
GPIO_SetBits(RS485_RE_GPIO,RS485_RE_PIN);////485发送使能
raw_delaynop(300);
while(dma_send_en!=0) //等待上次的DMA传输完成
{
counter ++;
if(counter >= 0xffff)
{
break;
}
}
dma_send_en = 1;
DMA_Cmd(DMA1_Channel7, DISABLE ); //关闭USART1 TX DMA1 所指示的通道
DMA1_Channel7 -> CMAR = (u32)send_buff;
DMA_SetCurrDataCounter(DMA1_Channel7,length); //设置传输长度
DMA_Cmd(DMA1_Channel7, ENABLE); //使能USART1 TX DMA1 所指示的通道
}
//初始化IO 串口2
//pclk1 CLK1时钟频率(Mhz)
//bound:波特率
static void Rs485_usart_init(u32 bound)
{
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2,ENABLE);//复位串口2
RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2,DISABLE);//停止复位
USART_InitStructure.USART_BaudRate = bound;//波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据长度
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;///奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式
USART_Init(RS485_UART, &USART_InitStructure); ; //初始化串口
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //使能串口2中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //先占优先级2级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 5; //从优先级2级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
USART_ClearITPendingBit(RS485_UART, USART_IT_TC);//清除中断TC位
USART_ClearITPendingBit(RS485_UART, USART_IT_TC);//清除中断TC位
USART_ITConfig(RS485_UART, USART_IT_IDLE, ENABLE); //开启IDLE中断
USART_ITConfig(RS485_UART, USART_IT_RXNE, DISABLE);//关闭RXNE中断
USART_Cmd(RS485_UART, ENABLE); //使能串口
GPIO_ResetBits(RS485_RE_GPIO,RS485_RE_PIN); //默认为接收模式
raw_delaynop(9250);
}
static void RS485_DMA_Init()
{
Rs485_usart_init(115200);
USART_DMACmd(RS485_UART,USART_DMAReq_Tx,ENABLE); //使能串口2的DMA发送
USART_DMACmd(RS485_UART,USART_DMAReq_Rx,ENABLE); //使能串口2的DMA接收
//DMA1通道7,外设为串口2,存储器为SendBuff,长度SEND_BUF_SIZE.
DMA1_Config(DMA1_Channel7,(uint32_t)&USART2->DR,(u32)Rs485_TX_Buf,TX_BUF_SIZE,0);
//DMA1_Enable(DMA1_Channel7,100);//开始一次DMA传输!
RS485_DMA_Send(Rs485_TX_Buf,100);
DMA_GetCurrDataCounter(DMA1_Channel6);
raw_delaynop(500);
DMA_GetCurrDataCounter(DMA1_Channel6);
raw_delaynop(500);
DMA1_Config(DMA1_Channel6,(uint32_t)&USART2->DR,(u32)Rs485_RX_Buf,RX_BUF_SIZE,1); //数据传输方向不同
}
void RS485_UART_IRQHandler(void)
{
raw_enter_interrupt();
uint8_t i;
uint8_t res;
if(USART_GetITStatus(RS485_UART, USART_IT_IDLE) != RESET) //监测到总线空闲
{
i = RS485_UART->SR;
i = RS485_UART->DR; //清除USART_IT_IDLE标志
DMA_Cmd(DMA1_Channel6, DISABLE); //读取数据前,先关闭DMA
i=100-DMA_GetCurrDataCounter(DMA1_Channel6);
DMA_SetCurrDataCounter(DMA1_Channel6,RX_BUF_SIZE);
DMA_Cmd(DMA1_Channel6, ENABLE ); //打开DMA
rs485_receive_flag=1;
rs485_receive_len=i;
}
raw_finish_int();
}
//RS485 DMA方式发送中断
void DMA1_Channel7_IRQHandler()
{
/* Clear DMA Stream Transfer Complete interrupt pending bit */
if ( DMA_GetFlagStatus(DMA1_FLAG_TC7)!=RESET )
{
DMA_Cmd(DMA1_Channel7, DISABLE);
DMA_ClearITPendingBit(DMA1_FLAG_TC7);
dma_send_en=0;
raw_delaynop(9250);
GPIO_ResetBits(RS485_RE_GPIO,RS485_RE_PIN);
raw_delaynop(9250);
}
}
void main()
{
RS485_DMA_Init();
while(1)
{
if(rs485_receive_flag==1&&rs485_receive_len!=0)
{
rs485_receive_flag=0;
{
rs485_receive_flag=0;
memcpy(Rs485_TX_Buf,Rs485_RX_Buf,rs485_receive_len);
RS485_DMA_Send(Rs485_TX_Buf,rs485_receive_len);
}
}
raw_delayms(5);
}
}
|
-
|