STM32
直播中

世态薄凉

8年用户 1170经验值
私信 关注
[问答]

如何去实现STM32串口printf函数的重定向呢

如何去实现STM32串口printf函数的重定向呢?

如何去实现STM32串口的中断接受和发送呢?

回帖(1)

李洪斌

2021-12-7 14:47:54
1:概述
1.1:本篇实现串口驱动,实现printf函数的重定向,实现串口的中断接受和发送,效仿modbus协议中的3.5T超时机制,判断是否接受完毕;
1.2:如果串口仅仅是实现一个控制台,打印一些debug数据,使用printf函数(串口发送数据忙等待),如果是需要用串口进行外设设备的控制,比如串口GPRS模块,需使用串口中断进行控制,因为受限于串口的传输速率,如果使用忙等待发送数据,会阻塞主程序中的其它任务;
1.3:使用sysclk作为超时定时器,sysclk的中断优先级需高于串口中断;
1.4:除过使用3.5T超时时间判断接受数据是否完成外,还可使用ASCLL码的形式,利用字符操作库函数,自定义串口通信协议;
1.5:开发板:stm32f103zert   软件环境:KEIL MKD5
1.6:115200 波特率,间隔1ms发送字符串 "PassWord",主程序将接收到"PassWord"后返回"123456rn",测试主程序响应迅速,不丢帧;






2:代码
main.c

#include "stm32f10x.h"
#include "usart_init.h"
#include "timer.h"
#include "Sys_Driver.h"

unsigned int baud[5] = {9600,14400,19200,56000,115200};
unsigned int T_35 = 0;     //串口发送3.5个字节的时间,由波特率得出,单位为ms

int main(void)
{
        T_35 = 3.5*(10000000/baud[4]);     
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);     //设置中断优先级分组
        Usart_Init(baud[4]);  //串口初始化
        SysTick_Init(INT_1US,SysTick_CLKSource_HCLK_Div8);  //sysclk初始化,设置1ms中断
        timer_set(&usart_timer,T_35);   //定义一个串口计时器
       
       
        while(1)
        {
                if(Start_Receive_Flag == 1)
                {
                        if(timer_expired(&usart_timer) == 1)   //3.5T时间到达,一条串口数据接受成功
                        {
                                Start_Receive_Flag = 0;
                                Usart_Handle_Func();
                        }
                }
        }
}

  usart_init.c


#include "usart_init.h"


u8 Usart_Receive_Ok = 0;
u8 Start_Receive_Flag = 0;

u8 Usart_TX_Buff[TX_RE_BUFF_LENGTH];
u8 Usart_RX_Buff[TX_RE_BUFF_LENGTH];
COMx_Define CYCLE;


/*******************printf()函数重定向***************/
//发送函数
int fputc(int ch, FILE *f)
{
        USART_SendData(USART2, (unsigned char) ch);
        while (!(USART2->SR & USART_FLAG_TXE));
        return (ch);
}

//接受函数
int fgetc(FILE *f)  
{
        while (!(USART2->SR & USART_FLAG_RXNE));
        return USART_ReceiveData(USART2);
}


void Usart_Init(u32 baud)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
         
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);          //使能USART2,GPIOA时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);        //使能USART2,GPIOA时钟
       
        //USART2_TX   PA.2
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;       
        GPIO_Init(GPIOA, &GPIO_InitStructure);
   
  //USART2_RX          PA.3
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

  //USART2 NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;    //抢占优先级2
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;                     //子优先级2
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                               //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);                                   //根据指定的参数初始化VIC寄存器
  
  //USART 初始化设置
        USART_InitStructure.USART_BaudRate = baud;        
        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_ITConfig(USART2, USART_IT_RXNE, ENABLE);  //开启发送完成中断和接收完成中断  
        USART_ITConfig(USART2,USART_IT_TC,ENABLE);  //开启发送完成中断和接收完成中断
        USART_Cmd(USART2, ENABLE);                                  //使能串口
}

void Usart_Send_Byte(u8 data)
{
        Usart_TX_Buff[CYCLE.TX_write] = data;      //装发送缓冲区
        if(++CYCLE.TX_write == TX_RE_BUFF_LENGTH)
                CYCLE.TX_write = 0;
       
        if(CYCLE.TX_busy == 0)                     //发送空闲
        {
                CYCLE.TX_busy = 1;
                USART_SendData(USART2,Usart_TX_Buff[CYCLE.TX_read]);  //想串口发送数据,触发中断
                if(++CYCLE.TX_read == TX_RE_BUFF_LENGTH)
                        CYCLE.TX_read = 0;
        }
}

/*串口发送函数*/
void Usart_Send_Data(u8 *ptr,u8 num)
{
        if(num == 0)                                   //发送字符串
        {
                for(;*ptr!='';ptr++)
                {
                        Usart_Send_Byte(*ptr);
                }
        }
        else                                           //发送num字节数据
        {
                for(;num>0;num--)
                {
                        Usart_Send_Byte(*ptr++);
                }
        }
}

/*串口接收函数,当接收到可用的数据帧时,对接收到的数据进行处理,main函数中调用*/
void Usart_Handle_Func(void)
{
        u8 i = 0;
        u8 Buff[40];
        while(CYCLE.RX_read != CYCLE.RX_write)
        {
                Buff[i++] = Usart_RX_Buff[CYCLE.RX_read];
                if(++CYCLE.RX_read == TX_RE_BUFF_LENGTH)
                        CYCLE.RX_read = 0;
        }
        Buff = '';
//        Usart_Send_Data(Buff,0);
//        Usart_Send_Data("rn",0);
        if(memcmp(Buff,"PassWord",8) == 0)
        {
                Usart_Send_Data("123456rn",0);
        }
}

///*中断处理函数*/
void USART2_IRQHandler(void)
{
        u8 data;
        if(USART_GetITStatus(USART2,USART_IT_TC) == SET)    //发送完成中断
        {
                USART_ClearITPendingBit(USART2,USART_IT_TC);
                if(CYCLE.TX_read != CYCLE.TX_write)
                {
                        USART_SendData(USART2,Usart_TX_Buff[CYCLE.TX_read]);
                        if(++CYCLE.TX_read == TX_RE_BUFF_LENGTH)
                                CYCLE.TX_read = 0;
                }
                else
                {
                        CYCLE.TX_busy = 0;                                 //缓冲区数据发送完成,串口总线空闲,可以开始发送新的数据
                }
        }
        else
        if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收完成中断
        {
                USART_ClearITPendingBit(USART2,USART_IT_RXNE);
                data = USART_ReceiveData(USART2);
                Usart_RX_Buff[CYCLE.RX_write] = data;
                if(++CYCLE.RX_write == TX_RE_BUFF_LENGTH)
                        CYCLE.RX_write = 0;
                timer_reset(&usart_timer);   //开始计时
                Start_Receive_Flag = 1;
        }
}
举报

更多回帖

×
20
完善资料,
赚取积分