上一篇是STM32F4的初级例程,主要就是对GPIO的操作。接下来要进行的就是Usart了,有时候我把想把某些中间量或者其他程序状态信息打印出来显示在电脑上,那么这是串口的作用就可想而知了。
STM32F407xx内嵌四个通用同步/异步接收器(USART1,USART2,USART3 和USART6)和两个通用异步收发器(UART4和UART5)。这6个接口提供异步通信的IrDASIR ENDEC支持,多机通信模式,单线半双工通信模式LIN主/从功能。 USART1和USART6接口能够速度高达10.5 Mbit / s的通信其他可用的接口通信高达5.25bit/s。USART1,USART2,USART3和USART6还提供硬件管理的CTS,RTS信号,智能卡的模式(ISO7816兼容)和类似的SPI通信能力。所有接口都可以通过DMA控制器。
这里我使用了两个线的最简单串口设置。
首先第一步就是串口初始化,配置Usart的GPIO、工作模式
/*************************************************************************************
* 函数名: USART2_Config
* 描述 : USART2 GPIO、工作模式的配置
* 输入 : 无
* 输出 : 无
* 批注 : PA2->TX PA3->RX
*************************************************************************************/
void USART2_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //初始化GPIO结构体
USART_InitTypeDef USART_InitStructure; //初始化Usart结构体
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能GPIOA的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); //使能USART2的时钟
GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2);
/* 配置USART2的GPIO */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 设置USART2的模式 */
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
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(USART2, &USART_InitStructure);
/* 打开USART2的中断 当接收接收寄存器不空时产生中断 */
USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
USART_Cmd(USART2, ENABLE); //使能USART2
}
第二步:由于我使用的usart的DMA模式发送数据,而且DMA的独有的数据处理模块,所以就得详细的说明一下。
什么是STM32的DMA?其全称是:Direct Memory Access;根据ST公司提供的相关信息,DMA是STM32中一个独立与Cortex-M3内核的模块,有点类似与ADC、PWM、TIMER等模块;主要功能是通信“桥梁”的作用,可以将所有外设映射的寄存器“连接”起来,这样就可以高速问各寄存器,其传输不受CPU的支配,传输还是双向的;例如,从“表面”上看,它可以将flash中的数据与储存器中变量建立通讯,还可以将一外设的积存器或缓冲器与另外设的寄存器或缓冲器建立双向通讯,有点像把外设硬件之间用“导线”连接在一起了。其间的通讯不占CPU资源,访问速度高,对于实时性强的应用将是一个很好的选择。下面就要看看DMA的具体配置了:
/*************************************************************************************
* 函数名: DMA_Config
* 描述 : DMA 串口初始化配置
* 输入 : 无
* 输出 : 无
* 批注 : 廖旭-2014年1月18日 10:42:12
*************************************************************************************/
void DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); //开启DMA时钟
NVIC_Config(); //配置DMA中断
/* 设置DMA的传输通道:DMA_Channel_4 */
DMA_InitStructure.DMA_Channel = DMA_Channel_4;
/* 设置DMA源:内存地址&串口数据寄存器地址 */
DMA_InitStructure.DMA_PeripheralBaseAddr = USART2_DR_Base;
/* 内存地址(要传输的变量的指针) */
DMA_InitStructure.DMA_Memory0BaseAddr = (u32)SendBuff;
/* 方向:从内存到外设 */
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
/* 传输大小DMA_BufferSize=SENDBUFF_SIZE */
DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;
/* 外设地址不增 */
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
/* 内存地址自增 */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
/* 外设数据单位 */
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
/* 内存数据单位 8bit */
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
/* DMA模式:一次传输,循环 */
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
/* 优先级:中 */
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
/* 指定如果FIFO模式或直接模式将用于指定的流 : 不使能FIFO模式*/
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
/* 指定了FIFO阈值水平 */
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
/* 指定的Burst转移配置内存传输 */
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
/* 指定的Burst转移配置外围转移 */
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
/* 配置DMA1的4通道 */
DMA_Init(DMA1_Stream6, &DMA_InitStructure);
/* Enable DMA */
DMA_Cmd(DMA1_Stream6,ENABLE);
/* 配置DMA发送完成后产生中断 */
DMA_ITConfig(DMA1_Stream6,DMA_IT_TC,ENABLE);
}
第三步:配置NVIC
(NestedVectoredInterruptController)嵌套向量中断控制器,配置中断向量的优先级和中断源。
/*************************************************************************************
* 函数名: NVIC_Config
* 描述 : DMA中断源和优先级的配置
* 输入 : 无
* 输出 : 无
* 批注 : 廖旭-2014年1月18日 10:42:12
*************************************************************************************/
void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure one bit for preemption priority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/* 配置P[A|B|C|D|E]0为中断源 */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream6_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void USART2_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the USARTx Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
第四步:添加串口和DMA中断函数,函数名是固定的:void DMAx_Streamy_IRQHandler(void) 其中x:DMA号,y:DMA通道。
串口中断函数名:void USARTx_IRQHandler(void) 其中x:串口号
/*******************************************************************************
* 函数名:USART2_IRQHandler
* 描述 :USART2的接收中断函数
* 输入 :无
* 输出 :无
* 批注 :廖旭-2014年1月14日 21:41:04
*******************************************************************************/
void USART2_IRQHandler(void)
{
// uint8_t data;
if(USART_GetFlagStatus(USART2,USART_FLAG_RXNE) != RESET)
{
printf("\n\r 接收成功! Receive data: %f\n\r",USART_ReceiveData(USART2));
USART2_printf(USART2,"Receive successful!");
USART_ClearITPendingBit(USART2,USART_IT_RXNE);
}
}
/*******************************************************************************
* 函数名:DMA1_Channel4_IRQHandler
* 描述 :DMA2发送完成中断函数
* 输入 :无
* 输出 :无
* 批注 :廖旭-2014年1月18日 15:43:43
*******************************************************************************/
void DMA1_Stream6_IRQHandler(void)
{
/* 判断是否为DMA发送完成中断 */
if(DMA_GetITStatus(DMA1_Stream6,DMA_IT_TCIF6) != RESET)
{
/* 关闭LED3,即:发送完成 */
STM_EVAL_LEDOff(LED3);
/* 串口向pc发送说明 */
USART2_printf(USART2,"串口向DMA发送完成");
/*清除标志位*/
DMA_ClearITPendingBit(DMA1_Stream6,DMA_IT_TCIF6);
}
}
最后就是看看主函数main.c了,这个就没什么可说了。
/*********************** (C) COPYRIGHT 2014 Liaoxu ******************************
* 文件名 :main.c
* 描述 :串口利用DMA向上位机发送数据,在发送过程中LED3点亮,当发送完成后LED3熄灭。
* 实验平台:STM32F_Discovery
* 库版本 :STM32F4
* 作者 :廖旭-2014年1月18日 15:30:13
**********************************************************************************/
#include "stm32f4xx.h"
#include "usart2_dma.h"
#include "led.h"
uint16_t i;
uint8_t SendBuff[SENDBUFF_SIZE];
int main(void)
{
USART2_Config();
DMA_Config();
NVIC_Config();
USART2_NVIC_Config();
STM_EVAL_LEDInit(LED3);
STM_EVAL_LEDInit(LED4);
/* 填充将要发送的数据 */
for(i = 0; i < SENDBUFF_SIZE; i++)
{
SendBuff[i] = 0xff;
}
/* 串口向pc发送说明 */
USART2_printf(USART2, "串口开始向DMA发送数据");
/* 串口向DMA发出请求 */
USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
/*
* 在DMA尚未传送完成时,cpu继续执行main函数中的代码,即:点亮LED3
* 而当DMA发送完成时,在中断函数关闭LED3
*/
STM_EVAL_LEDOn(LED3);
while(1);
}
/*********************** (C) COPYRIGHT 2014 Liaoxu ******************************/
我这里出现了一个问题,就是接收函数,当上位机给stm32发送数据的时候,只能同时发送2个十六进制的数,当发送多与2个,程序就不能执行了。
希望哪位高手看到我的博客能帮我解决一下,我自己也会想办法解决的,解决好了我会在这里声明的!