后续会开发 寄存器串口初始化和打印 目前使用的是标准库函数开发。
//更新说明 串口接收与DMA控制器结合(文章最下面会有代码 贴上)
开始直接上代码,代码里面有解释
#include "usart.h"
//------------------------------------------------修改以下宏定义可以配置相应的串口初始化----------------------------------------------------
#define USART_TX GPIO_Pin_9 //串口GPIO发送端口
#define USART_RX GPIO_Pin_10 //串口GPIO接收端口
#define USART_GPIO_TypeDef GPIOA //串口对应的GPIO位置
#define USART_Pin_TX GPIO_PinSource9 //串口映射发送的GPIO
#define USART_Pin_RX GPIO_PinSource10 //串口映射读取的GPIO
#define USART_RCC RCC_APB2Periph_USART1 // 注意串口1/6 是APB2总线 其它是APB1总线
#define USART_GPIO_RCC RCC_AHB1Periph_GPIOA //串口对应的GPIO总线
#define USART_IRQ USART1_IRQn //串口 中断号
#define USART USART1 //串口号
//------------------------------------------------修改以上宏定义可以配置相应的串口初始化----------------------------------------------------
/*
函数功能:初始化串口1
函数参数:uint32_t USART_BaudRate
函数返回值:无
函数描述:无
*/
void Usart1_Init(uint32_t USART_BaudRate)
{
GPIO_InitTypeDef GPIO_InitStruct; //串口GPIO结构体定义
USART_InitTypeDef USART_InitStruct; //串口结构体定义
NVIC_InitTypeDef NVIC_InitStruct; //总中断结构体定义
RCC_APB2PeriphClockCmd(USART_RCC,ENABLE); //使能串口外设的线 注意串口1/6 是APB2总线 其它是APB1总线
RCC_AHB1PeriphClockCmd(USART_GPIO_RCC,ENABLE); //使能串口对应的GPIO线
GPIO_PinAFConfig(USART_GPIO_TypeDef,USART_Pin_TX,GPIO_AF_USART1); //串口发送复用映射
GPIO_PinAFConfig(USART_GPIO_TypeDef,USART_Pin_RX,GPIO_AF_USART1); //串口接收复用映射
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Pin = USART_TX | USART_RX;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(USART_GPIO_TypeDef,&GPIO_InitStruct); //串口 发送/接受端口初始化
USART_InitStruct.USART_BaudRate = USART_BaudRate;
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;
USART_Init(USART,&USART_InitStruct); //串口初始化
USART_Cmd(USART,ENABLE);
USART_ReceiveData(USART); //初始化时候读取一次避免 一开始就有中断
USART_ITConfig(USART,USART_IT_RXNE,ENABLE); //读取中断配置
NVIC_InitStruct.NVIC_IRQChannel = USART_IRQ;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_InitStruct); //串口总中断初始化
}
/*
函数功能:printf函数重定向
函数参数:无
函数返回值:无
函数描述:无
*/
int fputc(int ch, FILE * f)
{
USART->DR = (unsigned char)ch; //USART是上面宏定义的 哪个串口初始化就打印那个串口
while((USART->SR & 0x80) == 0);
return ch;
}
//------------------------------------------------某个串口初始化和打印完成----------------------------------------------------
如上图是初始化串口1的函数。根据您所需的串口修改相应的宏,就可以初始化相应的串口,本人经过验证串口2也是可以适用的。代码里面给出注释了请认真阅读。
进过验证串口2也是可以的,若有不懂可私聊。
另外本人使用的是HSE晶振为8MHZ的,需要修改如下图,不然打印是乱码。
----------------------------------------------补充------------------------------------------------------
使用我的串口打印,要在keil里面配置一下,还有要包含头文件stdio.h
如图
后续来了 寄存器开发版本 基于stm32f4xx主控的
/*
函数功能:串口对应IO口初始化
函数参数:无
函数返回值:无
函数描述:无
*/
void Usart_Gpio_Init(void)
{
RCC->AHB1ENR |= (0X01 << 0); //GPIOA线时钟使能
GPIOA->MODER &= ~((0x3 << 18) | (0x3 << 20)); //配置GPIOA模式选择
GPIOA->MODER |= ((0x2 << 18) | (0x2 << 20)); //PA9 PA10选择复用功能
GPIOA->OTYPER &= ~(0x1 << 9); //配置GPIOA输出类型选择 PA9配置推挽输出
GPIOA->OSPEEDR &= ~((0x3 << 18)); //配置GPIOA输出速度选择
GPIOA->OSPEEDR |= (0x3 << 18); //PA9 输出速度 100MHZ/80MHZ
GPIOA->PUPDR &= ~(0x3 << 20); //配置GPIOA上下拉选择
GPIOA->PUPDR |= (0x2 << 20); //PA10输入下拉
GPIOA->ODR &= (unsigned short int)0x00; //初始化串口让输出寄存器为零
GPIOA->AFR[1] &= ~((0xf << 4) | (0xf << 8)); //配置PA9 PA10复用选择 AFx
GPIOA->AFR[1] |= ((0x7 << 4) | (0x7 << 8)); //PA9 PA10选择复用功能
}
/*
函数功能:初始化串口1
函数参数:uint32_t USART_BaudRate
函数返回值:无
函数描述:无
*/
void Usart1_Init(uint32_t USART_BaudRate)
{
float USARTDIV;
int DIV_Mantissa,DIV_Fraction;
RCC->APB2ENR |= (0X01 << 4); //USART1时钟使能
Usart_Gpio_Init();
USART1->CR1 &= ~((0X01 << 15) | (0X01 << 13) | (0X01 << 12) | (0X01 << 10) | (0X01 << 3) | (0X01 << 2));//配置USART1控制寄存器选择
USART1->CR1 |= ((0X01 << 3) | (0X01 << 2));//配置USART1控制寄存器
USART1->CR2 &= ~((0X01 << 13) | (0X01 << 12));//配置USART1控制寄存器选择 //配置USART1控制寄存器
USARTDIV = (5250000.0 / USART_BaudRate);
DIV_Mantissa = USARTDIV;
DIV_Fraction = (USARTDIV - DIV_Mantissa) * 16;
USART1->BRR &= (0X0000); //串口波特率选择
USART1->BRR |= (DIV_Mantissa << 4 | DIV_Fraction); //串口波特率选择
//以下是接收中断使用配置
USART1->CR1 |= (0X01 << 5);//RXNE中断使能
NVIC_SetPriority(USART1_IRQn,NVIC_EncodePriority(USART1_IRQn,2,2));
NVIC_EnableIRQ(USART1_IRQn); //使能中断USART1
USART1->CR1 |= (0X01 << 13); //使能串口1
}
/*
函数功能:printf函数重定向
函数参数:无
函数返回值:无
函数描述:无
*/
int fputc(int ch, FILE * f)
{
USART1->DR = (unsigned char)ch;
while(!(USART1->SR & (0x01 << 7)));
return ch;
}
fpuct()是printf函数底层用的函数 让printf函数打印输出到串口需要修改 fputc函数的指向
//更新的 串口与DMA结合 这与上面的代码无关
#include "usart.h"
/*
函数功能:初始化串口对应的管脚
函数参数:无
函数返回值:无
函数描述:初始化完管脚后 初始化串口
*/
void UsartPinInit(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //开始GPIOA时钟
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //复用
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10 ; //PA9 PA10
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; //无上下拉
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //100MHZ
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //让PA9复用成串口功能
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //让PA10复用成串口功能
}
/*
函数功能:初始化串口
函数参数:无
函数返回值:无
函数描述:使用DMA模式
*/
void Usart1Init(uint32_t USART_BaudRate)
{
USART_InitTypeDef USART_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
UsartPinInit();
USART_InitStruct.USART_BaudRate = USART_BaudRate; //波特率
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无固件
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //发送读取模式
USART_InitStruct.USART_Parity = USART_Parity_No; //无校验位
USART_InitStruct.USART_StopBits = USART_StopBits_1; //停止位1
USART_InitStruct.USART_WordLength = USART_WordLength_8b; //发送的数据长度 8位
USART_Init(USART1,&USART_InitStruct);
USART_Cmd(USART1,ENABLE);
NVIC_InitStruct.NVIC_IRQChannel = DMA2_Stream2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_InitStruct);
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
}
/*
函数功能:重定向printf
函数参数:无
函数返回值:无
函数描述:无
*/
#include <stdio.h>
int fputc(int ch, FILE *stream)
{
USART_SendData(USART1,(uint16_t)ch);
while(!USART_GetFlagStatus(USART1,USART_FLAG_TXE));
return ch;
}
DMA初始化
#include "dma.h"
/*
函数功能:DMA2初始化
函数参数:无
函数返回值:无
函数描述:DMA2 通道4 不用缓冲FIFO
*/
void Dma2Init(uint32_t DMA_Memory0BaseAddr,uint32_t DMA_PeripheralBaseAddr,uint32_t DMA_BufferSize)
{
DMA_InitTypeDef DMA_InitStruct;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
DMA_InitStruct.DMA_BufferSize = DMA_BufferSize;
DMA_InitStruct.DMA_Channel = DMA_Channel_4;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
DMA_InitStruct.DMA_Memory0BaseAddr = DMA_Memory0BaseAddr;
DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
DMA_InitStruct.DMA_PeripheralBaseAddr = DMA_PeripheralBaseAddr;
DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_Priority = DMA_Priority_VeryHigh;
DMA_Init(DMA2_Stream2,&DMA_InitStruct);
DMA_ITConfig(DMA2_Stream2,DMA_IT_TC,ENABLE);
DMA_Cmd(DMA2_Stream2,ENABLE);
}
DMA中断服务函数配置
接收到了 20个数据就进入中断
#include <stdio.h>
void DMA2_Stream2_IRQHandler(void)
{
if(DMA_GetITStatus(DMA2_Stream2,DMA_IT_TCIF2))
{
printf("12\r\n");
DMA_ClearITPendingBit(DMA2_Stream2,DMA_IT_TCIF2);
}
//TimingDelay_Decrement();
}
unsigned char usart_dat[20];
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Dma2Init((uint32_t)usart_dat,(uint32_t)&USART1->DR,20);
Usart1Init(115200);
printf("ok\r\n");
/* Infinite loop */
while (1)
{
}
}