找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2499|回复: 11
收起左侧

stm32怎么实现串口通讯

[复制链接]
ID:142059 发表于 2018-7-7 18:39 | 显示全部楼层
发不了文件啊,要重定向printf函数
回复

使用道具 举报

ID:142059 发表于 2018-7-10 10:05 | 显示全部楼层
Angle145 发表于 2018-7-7 18:39
发不了文件啊,要重定向printf函数

用到printf函数才需要重定向,直接用串中发送字节并不需要重定向,
回复

使用道具 举报

ID:142059 发表于 2018-7-10 10:12 | 显示全部楼层
你有51基础吗?Stm32和51不同的就只有中断函的书写方式,51是在函数体后加中断号来决定中断服务程序,而Stm32的中断函数是固定死的,中断函数名字在启动文件(汇编)里就定义好了,所以要使用stm32的串口只需要初使化对应的串口的引脚成输出和输入,并且打开引脚复用时钟,然后再配置串口控制寄存器(配置波特率停止位数据位奇偶校验等),其实这些都是死的,像模版一样记住就行。
回复

使用道具 举报

ID:142059 发表于 2018-7-10 10:26 | 显示全部楼层
/*************************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和电脑互动

评分

参与人数 1黑币 +8 收起 理由
初学者204 + 8 很给力!

查看全部评分

回复

使用道具 举报

ID:142059 发表于 2018-7-10 10:36 | 显示全部楼层
其实不难,你只需要知道stm32的中断函数是固定的就行,不能修改(我才不会跟说在启动文件里修改能修改)

007、串口例程(支持串口1、2、3、4、5).zip

2.77 MB, 下载次数: 14

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表