stm32怎么实现串口通讯,初学stm32,利用串口实现与单片机的发送和接收数据不会使用,还请各位大佬帮帮忙。。。。。,发不了文件啊,要重定向printf函数,网上有很多资料和例程,要学会查找资料和思考,买一个STM32的开发板,最好是资料丰富,售后支持好的,对照资料一步步学,很容易实现的。,找对应STM型号,了解简单的例程就行,
Angle145 发表于 2018-7-7 18:39
发不了文件啊,要重定向printf函数
用到printf函数才需要重定向,直接用串中发送字节并不需要重定向,,你有51基础吗?Stm32和51不同的就只有中断函的书写方式,51是在函数体后加中断号来决定中断服务程序,而Stm32的中断函数是固定死的,中断函数名字在启动文件(汇编)里就定义好了,所以要使用stm32的串口只需要初使化对应的串口的引脚成输出和输入,并且打开引脚复用时钟,然后再配置串口控制寄存器(配置波特率停止位数据位奇偶校验等),其实这些都是死的,像模版一样记住就行。,/*************************USART串口*****************************************/
#define PRINTF_COM USART1 //printf打印串口选择 可选:USART1、USART2、USART3、UART4、UART5
#pragma import(__use_no_semihosting)
struct __FILE
{
int handle;
};
FILE __stdout;
void _sys_exit(int x)
{
x = x;
}
int fputc(int ch, FILE *f)
{
OS_ENTER_CRITICAL();
USART_SendData(USART1, (uint8_t) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET);
OS_EXIT_CRITICAL();
return ch;
}
void USART_SendByte(USART_TypeDef *USART_COM,u8 c) //串口发送一个字节
{
while((USART_COM->SR&0X40)==0);//循环发送,直到发送完毕
USART_COM->DR = (u8)(c);
while((USART_COM->SR&0X40)==0);//循环发送,直到发送完毕
}
void USART_SendString(USART_TypeDef *USART_COM,unsigned char *s) //串口发送字符串函数
{
while(*s)
{
while((USART_COM->SR&0X40)==0);//循环发送,直到发送完毕
USART_COM->DR = (u8)(*s);
while((USART_COM->SR&0X40)==0);//循环发送,直到发送完毕
s++;
}
}
void USART_SendBuf(USART_TypeDef *USART_COM,unsigned char *buf,u16 len) //串口发送数组函数
{
while(len–)
{
while((USART_COM->SR&0X40)==0);//循环发送,直到发送完毕
USART_COM->DR = (u8)(*buf++);
while((USART_COM->SR&0X40)==0);//循环发送,直到发送完毕
}
}
void USART1_Config(u32 BaudRate) //串口1初始化函数
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//使能USART1,GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);
//GPIO端口设置
//USART1_TX GPIOA.9初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//USART 初始化设置
USART_InitStructure.USART_BaudRate = BaudRate;//串口波特率
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(USART1, &USART_InitStructure); //初始化串口1
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
USART_ClearFlag(USART1,USART_FLAG_TC);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启串口接受中断
USART_Cmd(USART1, ENABLE); //使能串口1
}
void USART2_Config(u32 BaudRate) //串口2初始化函数
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能GPIOA,D时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能USART2时钟
//GPIO端口设置
//TX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA2
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽
GPIO_Init(GPIOA, &GPIO_InitStructure);
//RX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //PA3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2,ENABLE); //复位串口2
RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2,DISABLE); //停止复位
USART_InitStructure.USART_BaudRate = BaudRate; //波特率设置
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(USART2, &USART_InitStructure); //初始化串口
USART_ClearFlag(USART2,USART_FLAG_TC);
//中断
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //使能串口2中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //先占优先级2级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级2级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断
USART_Cmd(USART2, ENABLE); //使能串口
}
void USART3_Config(u32 BaudRate) //串口3初始化函数
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitValue;
USART_InitTypeDef USART_InitValue;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
//GPIO端口设置
GPIO_InitValue.GPIO_Pin=GPIO_Pin_10;
GPIO_InitValue.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitValue.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOB,&GPIO_InitValue);
GPIO_InitValue.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitValue.GPIO_Pin =GPIO_Pin_11;
GPIO_Init(GPIOB,&GPIO_InitValue);
USART_InitValue.USART_BaudRate = BaudRate;
USART_InitValue.USART_WordLength = USART_WordLength_8b;
USART_InitValue.USART_StopBits = USART_StopBits_1;
USART_InitValue.USART_Parity = USART_Parity_No;
USART_InitValue.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitValue.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART3,&USART_InitValue);
USART_ClearFlag(USART3,USART_FLAG_TC);
USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);//配置串口接收非空中断
NVIC_InitStructure.NVIC_IRQChannel =USART3_IRQn ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =3; //抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能USART3中断
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART3,ENABLE);
}
void UART4_Config(u32 BaudRate) //串口4初始化函数
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//注意UART4是挂载在APB1总线上的,用RCC_APB1PeriphClockCmd()函数初始化!
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE);
//GPIO端口设置
//UART4_TX PC.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //将UART4 的TX 配置为复用推挽输出 AF_PP
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //输出速度50MHz
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //推挽输出模式 Out_PP
GPIO_Init(GPIOC, &GPIO_InitStructure);
//将UART4 的RX 配置为复用浮空输入 IN_FLOATING
//UART4_RX PC.11
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //浮空输入 IN_FLOATING
GPIO_Init(GPIOC, &GPIO_InitStructure);
//UART4配置 N 8 1
USART_InitStructure.USART_BaudRate = BaudRate; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长8位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //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; //打开Rx接收和Tx发送功能
USART_Init(UART4 , &USART_InitStructure);
//UART4 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
USART_ClearFlag(UART4,USART_FLAG_TC);
USART_ITConfig(UART4,USART_IT_RXNE,ENABLE);//配置串口接收非空中断
USART_Cmd(UART4,ENABLE);
}
void UART5_Config(u32 BaudRate) //串口5初始化函数
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5,ENABLE);
//GPIO端口设置
//UART5_TX PC.12
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //输出速度50MHz
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //推挽输出模式 Out_PP
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //将UART4 的TX 配置为复用推挽输出 AF_PP
GPIO_Init(GPIOC, &GPIO_InitStructure);
//将UART5 的RX 配置为复用浮空输入 IN_FLOATING
//UART5_RX PD.2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //浮空输入 IN_FLOATING
GPIO_Init(GPIOD, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = BaudRate; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长8位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //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; //打开Rx接收和Tx发送功能
USART_Init(UART5 , &USART_InitStructure);
/* Enable the UART5 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
USART_ClearFlag(UART5,USART_FLAG_TC);
USART_ITConfig(UART5,USART_IT_RXNE,ENABLE);//配置串口接收非空中断
USART_Cmd(UART5,ENABLE);
}
/*******************************串口END***************************************/
//串口1中断函数
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
res =USART_ReceiveData(USART1); //读取接收到的数据
USART_SendData(USART1,res);
}
}
//串口2中断函数
void USART2_IRQHandler(void)
{
u8 res;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收到数据
{
res =USART_ReceiveData(USART2); //读取接收到的数据
USART_SendData(USART2,res);
}
}
//串口3中断函数
void USART3_IRQHandler(void)
{
u8 res;
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) //接收到数据
{
res =USART_ReceiveData(USART3); //读取接收到的数据
USART_SendData(USART3,res);
}
}
//串口4中断函数
void UART4_IRQHandler(void)
{
u8 res;
if(USART_GetITStatus(UART4, USART_IT_RXNE) != RESET) //接收到数据
{
res =USART_ReceiveData(UART4); //读取接收到的数据
USART_SendData(UART4,res);
}
}
//串口5中断函数
void UART5_IRQHandler(void)
{
u8 res;
if(USART_GetITStatus(UART5, USART_IT_RXNE) != RESET) //接收到数据
{
res =USART_ReceiveData(UART5); //读取接收到的数据
USART_SendData(UART5,res);
}
}
//注:中断函数名是固定的,不能更改(可在启动文件里更改,不建议更改),
//串口使用方法:想要哪个串口就初使化哪个串口,然后用发送函数就可以发送数据,当然,这里提供了printf重定向了,你也可以直接用printf函数发送。
//使用示例:
int main(void)
{
USART1_Config(9600); //初使化串口1,波特率为9600
while(1)
{
printf(“你好! \r\n”); //\r\n是回车符
}
}
//接收串口数据在串口1中断函数里接收,和51一样。
//串口1 引脚: PA9: TXD PA10:RXD
//串口2 引脚: PA2: TXD PA3: RXD
//串口3 引脚: PB10:TXD PB11:RXD
//串口4 引脚: PC10:TXD PC11:RXD
//串口5 引脚: PC12:TXD PD2: RXD
//ps:stm32只有串口1支持串口下载烧写程序,所以我们一般都用串口1和电脑互动,其实不难,你只需要知道stm32的中断函数是固定的就行,不能修改(我才不会跟说在启动文件里修改能修改),这有原子哥的例程,建议网上查找原子、硬石等开发板的源码,也可以购买一块,按照里面的例程来学习,这样学的比较快