一直都没有机会用STM32做什么项目,好在公司产品要平台升级,用到了STM32,所以最近在调试STM32,先说USART,后面再来说I 硬件平台:STM 开发环境:KEIL 4; 先说说应用通讯模式,串口终端的工作方式和迪文屏差不多,终端被动接受MCU发的指令,终端会偶尔主动发送一些数据给MCU(像迪文屏的触摸信息上传)。 串口DMA发送: 发送数据的流程: 前台程序中有数据要发送,则需要做如下几件事 1. 在数据发送缓冲区内放好要发送的数据,说明:此数据缓冲区的首地址必须要在DMA初始化的时候写入到DMA配置中去。 2. 将数据缓冲区内要发送的数据字节数赋值给发送DMA通道,(串口发送DMA和串口接收DAM不是同一个DMA通道) 3. 开启DMA,一旦开启,则DMA开始发送数据,说明一下:在KEIL调试好的时候,DMA和调试是不同步的,即不管Keil 是什么状态,DMA总是发送数据。 4. 等待发送完成标志位,即下面的终端服务函数中的第3点设置的标志位。或者根据自己的实际情况来定,是否要一直等待这个标志位,也可以通过状态机的方式来循环查询也可以。或者其他方式。 判断数据发送完成: 启动DMA并发送完后,产生DMA发送完成中断,在中断函数中做如下几件事: 1. 清DMA发送完成中断标志位 2. 关闭串口发送DMA通道 3. 给前台程序设置一个软件标志位,说明数据已经发送完毕 串口DMA接收: 接收数据的流程: 串口接收DMA在初始化的时候就处于开启状态,一直等待数据的到来,在软件上无需做任何事情,只要在初始化配置的时候设置好配置就可以了。 判断数据数据接收完成: 这里判断接收完成是通过串口空闲中断的方式实现,即当串口数据流停止后,就会产生IDLE中断。这个中断里面做如下几件事: 1. 关闭串口接收DMA通道,2点原因:1.防止后面又有数据接收到,产生干扰。2.便于DMA的重新配置赋值,下面第4点。 2. 清除DMA 所有标志位 3. 从DMA寄存器中获取接收到的数据字节数 4. 重新设置DMA下次要接收的数据字节数,注意,这里是给DMA寄存器重新设置接收的计数值,这个数量只能大于或者等于可能接收的字节数,否则当DMA接收计数器递减到0的时候,又会重载这个计数值,重新循环递减计数,所以接收缓冲区的数据则会被覆盖丢失。 5. 开启DMA通道,等待下一次的数据接收,注意,对DMA的相关寄存器配置写入,如第4条的写入计数值,必须要在关闭DMA的条件进行,否则操作无效。 说明一下,STM32的IDLE的中断在串口无数据接收的情况下,是不会一直产生的,产生的条件是这样的,当清除IDLE标志位后,必须有接收到第一个数据后,才开始触发,一断接收的数据断流,没有接收到数据,即产生IDLE中断。 USART 和 DMA 硬件初始化配置
/*--- LumModule
#define LUMMOD_UART #define #define #define #define LUMMOD_UART_RxPin #define #define #define
#define #define LUMMOD_UART_Tx_DMA_FLAG #define
#define #define #define
void { NVIC_InitTypeDef NVIC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure;
/* System Clocks Configuration */ //= System Clocks /* Enable GPIO clock */ RCC_APB2PeriphClockCmd(LUMMOD_UART_GPIO_CLK , /* Enable USART Clock */ RCC_APB1PeriphClockCmd(LUMMOD_UART_CLK, //=NVIC_Configuration==============================================================================//
/* Configure the NVIC Preemption Priority NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
/* Enable the DMA Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority NVIC_InitStructure.NVIC_IRQChannelSubPriority NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
/* Enable the USART Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority NVIC_InitStructure.NVIC_IRQChannelSubPriority NVIC_InitStructure.NVIC_IRQChannelCmd = NVIC_Init(&NVIC_InitStructure); //=GPIO_Configuration==============================================================================//
GPIO_PinRemapConfig(GPIO_PartialRemap_USART3, /* Configure USART3 Rx as input floating */ GPIO_InitStructure.GPIO_Mode = GPIO_InitStructure.GPIO_Pin = GPIO_Init(LUMMOD_UART_GPIO,
/* Configure USART3 Tx as alternate function GPIO_InitStructure.GPIO_Speed = GPIO_InitStructure.GPIO_Mode = GPIO_InitStructure.GPIO_Pin = GPIO_Init(LUMMOD_UART_GPIO,
DMA_Uart_Init(); // 串口 DMA 配置
/* USART Format configuration
USART_InitStructure.USART_WordLength = USART_InitStructure.USART_StopBits = USART_InitStructure.USART_Parity = USART_InitStructure.USART_HardwareFlowControl USART_InitStructure.USART_Mode =
/* Configure USART3 */ USART_InitStructure.USART_BaudRate = 115200; USART_Init(LUMMOD_UART,
/* Enable USART3 Receive and Transmit USART_ITConfig(LUMMOD_UART, USART_IT_IDLE, /* Enable the USART3 */ USART_Cmd(LUMMOD_UART, ENABLE); // 开启串口 /* Enable USARTy DMA TX request */ USART_DMACmd(LUMMOD_UART, USART_DMAReq_Tx, USART_DMACmd(LUMMOD_UART, USART_DMAReq_Rx, }
void { DMA_InitTypeDef DMA_InitStructure; /* DMA clock enable */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, //=DMA_Configuration==============================================================================//
/*---
DMA_Cmd(LUMMOD_UART_Tx_DMA_Channel, DMA_DeInit(LUMMOD_UART_Tx_DMA_Channel); // 恢复缺省值 DMA_InitStructure.DMA_PeripheralBaseAddr = DMA_InitStructure.DMA_MemoryBaseAddr = DMA_InitStructure.DMA_DIR = DMA_InitStructure.DMA_BufferSize = DMA_InitStructure.DMA_PeripheralInc = DMA_InitStructure.DMA_MemoryInc = DMA_InitStructure.DMA_PeripheralDataSize = DMA_InitStructure.DMA_MemoryDataSize = DMA_InitStructure.DMA_Mode = DMA_InitStructure.DMA_Priority = DMA_InitStructure.DMA_M DMA_Init(LUMMOD_UART_Tx_DMA_Channel, DMA_ClearFlag(LUMMOD_UART_Tx_DMA_FLAG); // 清除DMA所有标志 DMA_Cmd(LUMMOD_UART_Tx_DMA_Channel, DISABLE); // 关闭DMA DMA_ITConfig(LUMMOD_UART_Tx_DMA_Channel, /*--- LUMMOD_UART_Rx_DMA_Channel
DMA_Cmd(LUMMOD_UART_Rx_DMA_Channel, DMA_DeInit(LUMMOD_UART_Rx_DMA_Channel); // 恢复缺省值 DMA_InitStructure.DMA_PeripheralBaseAddr = DMA_InitStructure.DMA_MemoryBaseAddr = DMA_InitStructure.DMA_DIR = DMA_InitStructure.DMA_BufferSize = DMA_InitStructure.DMA_PeripheralInc = DMA_InitStructure.DMA_MemoryInc = DMA_InitStructure.DMA_PeripheralDataSize = DMA_InitStructure.DMA_MemoryDataSize = DMA_InitStructure.DMA_Mode = DMA_InitStructure.DMA_Priority = DMA_InitStructure.DMA_M DMA_Init(LUMMOD_UART_Rx_DMA_Channel, DMA_ClearFlag(LUMMOD_UART_Rx_DMA_FLAG); // 清除DMA所有标志 DMA_Cmd(LUMMOD_UART_Rx_DMA_Channel, ENABLE); // 开启接收DMA通道,等待接收数据 } void BSP_Init(void) { Uart_Init(); }
//============================================================// DMA 发送应用源码
void { if(DMA_GetITStatus(DMA1_FLAG_TC2)) { LumMod_Uart_DAM_Tx_Over(); } } void { DMA_ClearFlag(LUMMOD_UART_Tx_DMA_FLAG); // 清除标志 DMA_Cmd(LUMMOD_UART_Tx_DMA_Channel, OSMboxPost(mbLumModule_Tx, (void*)1); // 设置标志位,这里我用的是UCOSII ,可以根据自己的需求进行修改 }
void { uint8 err; uint8 LumMod_Tx_Index ;
LumMod_Tx_Index = 0; LumMod_Tx_Buf[LumMod_Tx_Index++] = 1; LumMod_Tx_Buf[LumMod_Tx_Index++] = 2; LumMod_Tx_Buf[LumMod_Tx_Index++] = 3; LumMod_Tx_Buf[LumMod_Tx_Index++] = 4; LumMod_Tx_Buf[LumMod_Tx_Index++] = 5; LumMod_Tx_Buf[LumMod_Tx_Index++] = 6; LumMod_Tx_Buf[LumMod_Tx_Index++] = 7; LumMod_Tx_Buf[LumMod_Tx_Index++] = 8; LumMod_Uart_Start_DMA_Tx( LumMod_Tx_Index ); OSMboxPend(mbLumModule_Tx, 0, &err); }
void { LUMMOD_UART_Tx_DMA_Channel->CNDTR = DMA_Cmd(LUMMOD_UART_Tx_DMA_Channel, ENABLE); //开始DMA发送 }
//============================================================// DMA 接收应用源码
void { if(USART_GetITStatus(USART3, USART_IT_IDLE) { LumMod_Uart_DMA_Rx_Data(); USART_ReceiveData( USART3 ); // Clear } } void { DMA_Cmd(LUMMOD_UART_Rx_DMA_Channel, DMA_ClearFlag( LUMMOD_UART_Rx_DMA_FLAG ); // 清DMA标志位 LumMod_Rx_Data.index = LUMMOD_RX_BSIZE - LUMMOD_UART_Rx_DMA_Channel->CNDTR = DMA_Cmd(LUMMOD_UART_Rx_DMA_Channel, ENABLE); /* DMA 开启,等待数据。注意,如果中断发送数据帧的速率很快,MCU来不及处理此次接收到的数据,中断又发来数据的话,这里不能开启,否则数据会被覆盖。有2种方式解决。 1. 在重新开启接收DMA通道之前,将LumMod_Rx_Buf缓冲区里面的数据复制到另外一个数组中,然后再开启DMA,然后马上处理复制出来的数据。 2. 建立双缓冲,在LumMod_Uart_DMA_Rx_Data函数中,重新配置DMA_MemoryBaseAddr 的缓冲区地址,那么下次接收到的数据就会保存到新的缓冲区中,不至于被覆盖。*/ OSMboxPost(mbLumModule_Rx, LumMod_Rx_Buf); // 发送接收到新数据标志,供前台程序查询 }
也知道写些什么了,基本上就是这么多了。欢迎交流,共同提高! |
|
来自: goodwangLib > 《STM32》