STM32F1系列大容量型号串口12345单字节多字节收发实现

代码在型号为STM32F103VET6测试验证通过
以下为所有代码
串口1工程包含的代码文件有如下几个文件
timer2.h

#ifndef _TIMER2_H
#define _TIMER2_H

#include "config.h"

void TIM2Init(u16 period, u16 prescaler);//中断处理函数放在stm32f10x_it.c文件

#endif

timer2.c

#include "timer2.h"

/* TIM2中断优先级配置函数, */
void NVIC_TIM2Enable(void)
{
    NVIC_InitTypeDef NVIC_initstructure;

    NVIC_initstructure.NVIC_IRQChannel = TIM2_IRQn;           //选择TIM2中断通道
    NVIC_initstructure.NVIC_IRQChannelCmd = ENABLE;           //使能中断通道
    NVIC_initstructure.NVIC_IRQChannelPreemptionPriority = 0; //设定抢占优先级为0
    NVIC_initstructure.NVIC_IRQChannelSubPriority = 0;        //设定响应优先级为0
    NVIC_Init(&NVIC_initstructure);
}

/* 定时器2初始化函数,period-计数周期,Prescaler-预分频值 */
void TIM2Init(u16 period, u16 prescaler)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);        //使能TIM2时钟
    TIM_TimeBaseStructure.TIM_Period = period-1;                //设定自动重装载计数值
    TIM_TimeBaseStructure.TIM_Prescaler = prescaler-1;          //设定预分频系数   计数时钟=定时器时钟/(分频系数+1)
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;                //基本定时器没有时钟分频功能,此项会被忽略
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置向上计数模式 基本定时器只有向上
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);             //初始化TIM2
    NVIC_TIM2Enable();                                          //初始化TIM2中断优先级
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);                 //清除中断标志位,否则启动中断会先进中断服务函数
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE );                 //使能TIM2中断
    TIM_Cmd(TIM2, ENABLE);                                      //使能TIM2定时器
}

uart1.h

#ifndef _UART1_H
#define _UART1_H
#include "config.h"

#define BAUD1 9600//波特率宏定义
void USART1Init(u32 baud);//初始化串口和配置波特率


#endif

uart1.c

#include "uart1.h"

/* USART1引脚初始化 */
void USART1_IOInit(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;             //TXD引脚-PA9
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;       //TXD设置为复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     //输出速率50MHz
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;            //RXD引脚-PA10
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/* USART1中断优先级初始化 */
void NVIC_USART1Enable(void)  
{
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);    //
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;         //选择USART1中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //设置抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //设置响应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //使能通道
    NVIC_Init(&NVIC_InitStructure);
}

/* USART1模块初始化函数, baud-波特率 */
void USART1Init(u32 baud)
{
    USART_InitTypeDef USART_InitStructure;
    
    USART1_IOInit();                                            //USART1引脚初始化
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);      //使能USART1时钟,USART时钟在AP2上,其它4个串口在AP1上
    USART_InitStructure.USART_BaudRate = baud;                  //设置波特率为baud
    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_Tx|USART_Mode_Rx; //选择USART发送和接收模式
    USART_Init(USART1, &USART_InitStructure);                     //初始化USART1
    NVIC_USART1Enable();                          //USART1中断优先级初始化
    USART_ITConfig(USART1,USART_IT_RXNE, ENABLE); //开启串口接受中断
    USART_Cmd(USART1,ENABLE);                     //使能USART11
}




uart1_handle.h

#ifndef _UART1_HANDLE_H
#define _UART1_HANDLE_H
#include"config.h"


#define JIANGE_TIME1 30//帧间隔时间宏定义


void UartWrite1(unsigned char *buf, unsigned char len);//串口数据写入,即串口发送函数
unsigned char UartRead1(unsigned char *buf, unsigned char len);//串口数据读取函数
void UartRxMonitor1(unsigned char ms);//串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔
void UartAction1(unsigned char *buf, unsigned char len);//串口动作函数,根据接收到的命令帧执行响应的动作
void UartDriver1(void);//串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用
void UartSendByte1(void);/* 从串口发送一字节数据,需在串口发送中断中调用 */
extern unsigned char cntRxd1;   //接收字节计数器
extern unsigned char bufRxd1[60];  //接收字节缓冲区

#endif

uart1_handle.c

#include "uart1_handle.h"



unsigned char flagFrame1=0;
unsigned char cntRxd1 = 0;   //接收字节计数器
unsigned char bufRxd1[60];  //接收字节缓冲区
unsigned char bufTxd1[60]; //数据发送缓冲区

int  bufTxdPosition1 = 0;   //缓冲区发送数据的最后位置
int  bufWritePosition1 = 0; //向缓冲区写入数据的最后位置

/* 串口数据写入,即串口发送函数,buf-待发送数据的指针,len-指定的发送长度 */
void UartWrite1(unsigned char *buf, unsigned char len)
{

    while (len--)   //循环发送所有字节
    {
        bufTxd1[bufWritePosition1] = *buf++;//待发送数据逐一复制到发送缓冲区
        bufWritePosition1++;//向缓冲区写入数据的最后位置
    }
    USART_ITConfig(USART1, USART_IT_TXE, ENABLE); //开启发送中断发送数据
}


void UartSendByte1(void)/* 从串口发送一字节数据,需在串口发送中断中调用 */
{
    if (bufTxdPosition1 != bufWritePosition1) //最后发送位置与写入位置不等,说明还有需要发送的数据
    {
        USART_SendData(USART1, bufTxd1[bufTxdPosition1]); //发出最后位置上的数据
        bufTxdPosition1++;          //至缓冲区结尾时归零
   
    }
    else                                    //最后发送位置与写入位置相等,说明写入的数据已发送完
    {
        bufTxdPosition1=0;
        bufWritePosition1=0;
        USART_ITConfig(USART1, USART_IT_TXE, DISABLE);    //关闭发送中断,终止本次发送
        
    }
}



/* 串口数据读取函数,buf-接收指针,len-指定的读取长度,返回值-实际读到的长度 */
unsigned char UartRead1(unsigned char *buf, unsigned char len)
{
    unsigned char i;
    
    if (len > cntRxd1)  //指定读取长度大于实际接收到的数据长度时,
    {                  //读取长度设置为实际接收到的数据长度
        len = cntRxd1;
    }
    for (i=0; i<len; i++)  //拷贝接收到的数据到接收指针上
    {
        *buf++ = bufRxd1[i];
    }
    cntRxd1 = 0;  //接收计数器清零
    
    return len;  //返回实际读取长度
}


void UartRxMonitor1(unsigned char ms)/* 串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔 */
{
    static unsigned char cntbkp = 0;
    static unsigned char idletmr = 0;

    if (cntRxd1 > 0)  //接收计数器大于零时,监控总线空闲时间
    {
        if (cntbkp != cntRxd1)  //接收计数器改变,即刚接收到数据时,清零空闲计时
        {
            cntbkp = cntRxd1;
            idletmr = 0;
        }
        else                   //接收计数器未改变,即总线空闲时,累积空闲时间
        {
            if (idletmr < JIANGE_TIME1)  //空闲计时小于30ms时,持续累加
            {
                idletmr += ms;
                if (idletmr >= JIANGE_TIME1)  //空闲时间达到30ms时,即判定为一帧接收完毕
                {
                    flagFrame1 = 1;  //设置帧接收完成标志
						 
                }
            }
        }
    }
    else
    {
        cntbkp = 0;
    }
}


/* 串口动作函数,根据接收到的命令帧执行响应的动作
   buf-接收到的命令帧指针,len-命令帧长度 */
void UartAction1(unsigned char *buf, unsigned char len)
{
    UartWrite1(buf,len);
   
}





/* 串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用 */
void UartDriver1()
{
    unsigned char len;
    unsigned char buf[60];

    if (flagFrame1) //有命令到达时,读取处理该命令
    {
        flagFrame1 = 0;
       
        len = UartRead1(buf, sizeof(buf)); //将接收到的命令读取到缓冲区中
        
        UartAction1(buf, len);  //传递数据帧,调用动作执行函数
		

    }
}



stm32f10x_it.c

#include "stm32f10x_it.h"
#include "uart1_handle.h"
void TIM2_IRQHandler(void)
{

    if (TIM_GetITStatus(TIM2, TIM_FLAG_Update) == SET) //检测是否为定时器溢出中断
    {
        TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update);  //清除中断标志位      
        
        UartRxMonitor1(1);/* 串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔 */
       
    }
}

void  USART1_IRQHandler(void)
{
   
    if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET)  //检测接收中断标志位    
    {
      if (cntRxd1 < sizeof(bufRxd1)) //接收缓冲区尚未用完时,
       {                            //保存接收字节,并递增计数器

            bufRxd1[cntRxd1++] =USART_ReceiveData(USART1);  //读取接收到的数据

			
       }
    }
    
    
    if(USART_GetITStatus(USART1, USART_IT_TXE) == SET)  //检测发送中断标志位    
    {
        UartSendByte1();
    }    
}

main.c

#include "timer2.h"
#include "uart1.h"
#include "uart1_handle.h"


int main(void)
{	
    TIM2Init(10, 7200);//配置定时器定时1MS
    USART1Init(BAUD1);//初始化串口和配置波特率
	while (1)
    {
    
        UartDriver1();//串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用
     
    }
	
}

串口2工程包含的代码文件有如下几个文件
timer2.h

#ifndef _TIMER2_H
#define _TIMER2_H

#include "config.h"

void TIM2Init(u16 period, u16 prescaler);//中断处理函数放在stm32f10x_it.c文件

#endif

timer2.c

#include "timer2.h"

/* TIM2中断优先级配置函数, */
void NVIC_TIM2Enable(void)
{
    NVIC_InitTypeDef NVIC_initstructure;

    NVIC_initstructure.NVIC_IRQChannel = TIM2_IRQn;           //选择TIM2中断通道
    NVIC_initstructure.NVIC_IRQChannelCmd = ENABLE;           //使能中断通道
    NVIC_initstructure.NVIC_IRQChannelPreemptionPriority = 0; //设定抢占优先级为0
    NVIC_initstructure.NVIC_IRQChannelSubPriority = 0;        //设定响应优先级为0
    NVIC_Init(&NVIC_initstructure);
}

/* 定时器2初始化函数,period-计数周期,Prescaler-预分频值 */
void TIM2Init(u16 period, u16 prescaler)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);        //使能TIM2时钟
    TIM_TimeBaseStructure.TIM_Period = period-1;                //设定自动重装载计数值
    TIM_TimeBaseStructure.TIM_Prescaler = prescaler-1;          //设定预分频系数   计数时钟=定时器时钟/(分频系数+1)
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;                //基本定时器没有时钟分频功能,此项会被忽略
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置向上计数模式 基本定时器只有向上
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);             //初始化TIM2
    NVIC_TIM2Enable();                                          //初始化TIM2中断优先级
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);                 //清除中断标志位,否则启动中断会先进中断服务函数
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE );                 //使能TIM2中断
    TIM_Cmd(TIM2, ENABLE);                                      //使能TIM2定时器
}

uart2.h

#ifndef _UART2_H
#define _UART2_H
#include "config.h"




#define BAUD2 9600  //波特率宏定义
void USART2Init(u32 baud);//初始化串口2和配置波特率


#endif

uart2.c

#include "uart2.h"

/* USART2引脚初始化 */
void USART2_IOInit(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;             //TXD引脚-PA2  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;       //TXD设置为复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     //输出速率50MHz
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;            //RXD引脚-PA3
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //RXD上拉输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);
	
}
/* USART2中断优先级初始化 */
void NVIC_USART2Enable(void)  
{
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);    //
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;         //选择USART2中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //设置抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //设置响应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //使能通道
    NVIC_Init(&NVIC_InitStructure);
}

/* USART2模块初始化函数, baud-波特率 */
void USART2Init(u32 baud)
{
    USART_InitTypeDef USART_InitStructure;
    
    USART2_IOInit();     	//USART2引脚初始化
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);      //使能USART2时钟
    USART_InitStructure.USART_BaudRate = baud;                  //设置波特率为baud
    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_Tx|USART_Mode_Rx; //选择USART发送和接收模式
    USART_Init(USART2, &USART_InitStructure);                     //初始化USART2
    NVIC_USART2Enable();                          //USART2中断优先级初始化
    USART_ITConfig(USART2,USART_IT_RXNE, ENABLE); //开启串口2接受中断
    USART_Cmd(USART2,ENABLE);                     //使能USART2
}

uart2_handle.h

#ifndef _UART2_HANDLE_H
#define _UART2_HANDLE_H
#include"config.h"

#define JIANGE_TIME2 30//帧间隔时间宏定义


unsigned char UartRead2(unsigned char *buf, unsigned char len);//串口数据读取函数
void UartRxMonitor2(unsigned char ms);//串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔
void UartAction2(unsigned char *buf, unsigned char len);//串口动作函数,根据接收到的命令帧执行响应的动作
void UartDriver2(void);//串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用
void UartSendByte2(void);/* 从串口发送一字节数据,需在串口发送中断中调用 */
void UartWrite2(unsigned char *buf, unsigned char len);
extern unsigned char cntRxd2;   //接收字节计数器
extern unsigned char bufRxd2[60];  //接收字节缓冲区

#endif

uart2_handle.c

#include "uart2_handle.h"



unsigned char flagFrame2 = 0;  //帧接收完成标志,即接收到一帧新数据


unsigned char cntRxd2 = 0;   //接收字节计数器
unsigned char bufRxd2[60];  //接收字节缓冲区
unsigned char bufTxd2[60]; //数据发送缓冲区
int  bufTxdPosition2 = 0;   //缓冲区发送数据的最后位置
int  bufWritePosition2 = 0; //向缓冲区写入数据的最后位置

/* 串口数据写入,即串口发送函数,buf-待发送数据的指针,len-指定的发送长度 */
void UartWrite2(unsigned char *buf, unsigned char len)
{

    while (len--)   //循环发送所有字节
    {
        bufTxd2[bufWritePosition2] = *buf++;//待发送数据逐一复制到发送缓冲区
        bufWritePosition2++;//向缓冲区写入数据的最后位置
    }
    USART_ITConfig(USART2, USART_IT_TXE, ENABLE); //开启发送中断发送数据
}


void UartSendByte2(void)/* 从串口发送一字节数据,需在串口发送中断中调用 */
{
    if (bufTxdPosition2 != bufWritePosition2) //最后发送位置与写入位置不等,说明还有需要发送的数据
    {
        USART_SendData(USART2, bufTxd2[bufTxdPosition2]); //发出最后位置上的数据
        bufTxdPosition2++;          //至缓冲区结尾时归零
   
    }
    else                                    //最后发送位置与写入位置相等,说明写入的数据已发送完
    {
        bufTxdPosition2=0;
        bufWritePosition2=0;
        USART_ITConfig(USART2, USART_IT_TXE, DISABLE);    //关闭发送中断,终止本次发送
        
    }
}



/* 串口数据读取函数,buf-接收指针,len-指定的读取长度,返回值-实际读到的长度 */
unsigned char UartRead2(unsigned char *buf, unsigned char len)
{
    unsigned char i;
    
    if (len > cntRxd2)  //指定读取长度大于实际接收到的数据长度时,
    {                  //读取长度设置为实际接收到的数据长度
        len = cntRxd2;
    }
    for (i=0; i<len; i++)  //拷贝接收到的数据到接收指针上
    {
        *buf++ = bufRxd2[i];
    }
    cntRxd2 = 0;  //接收计数器清零
    
    return len;  //返回实际读取长度
}


void UartRxMonitor2(unsigned char ms)/* 串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔 */
{
    static unsigned char cntbkp = 0;
    static unsigned char idletmr = 0;

    if (cntRxd2 > 0)  //接收计数器大于零时,监控总线空闲时间
    {
        if (cntbkp != cntRxd2)  //接收计数器改变,即刚接收到数据时,清零空闲计时
        {
            cntbkp = cntRxd2;
            idletmr = 0;
        }
        else                   //接收计数器未改变,即总线空闲时,累积空闲时间
        {
            if (idletmr < JIANGE_TIME2)  //空闲计时小于30ms时,持续累加
            {
                idletmr += ms;
                if (idletmr >= JIANGE_TIME2)  //空闲时间达到30ms时,即判定为一帧接收完毕
                {
                    flagFrame2 = 1;  //设置帧接收完成标志
						 
                }
            }
        }
    }
    else
    {
        cntbkp = 0;
    }
}


/* 串口动作函数,根据接收到的命令帧执行响应的动作
   buf-接收到的命令帧指针,len-命令帧长度 */
void UartAction2(unsigned char *buf, unsigned char len)
{

          		
    UartWrite2(buf,len);							 	  
			 			        	 
  
      
}





/* 串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用 */
void UartDriver2()
{
    unsigned char len;
    unsigned char buf[30];

    if (flagFrame2) //有命令到达时,读取处理该命令
    {
        flagFrame2 = 0;
       
        len = UartRead2(buf, sizeof(buf)); //将接收到的命令读取到缓冲区中
        
        UartAction2(buf, len);  //传递数据帧,调用动作执行函数
		

    }
}



stm32f10x_it.c

#include "stm32f10x_it.h"
#include "uart2_handle.h"

void TIM2_IRQHandler(void)
{

    if (TIM_GetITStatus(TIM2, TIM_FLAG_Update) == SET) //检测是否为定时器溢出中断
    {
        TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update);  //清除中断标志位
      
        

        UartRxMonitor2(1);/* 串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔 */
       
    }
}

void  USART2_IRQHandler(void)
{
   
    if(USART_GetITStatus(USART2,USART_IT_RXNE) == SET)  //检测接收中断标志位    
    {
      if (cntRxd2 < sizeof(bufRxd2)) //接收缓冲区尚未用完时,
       {                            //保存接收字节,并递增计数器

            bufRxd2[cntRxd2++] =USART_ReceiveData(USART2);  //读取接收到的数据
			
       }
    }
    
    if(USART_GetITStatus(USART2, USART_IT_TXE) == SET)  //检测发送中断标志位    
    {
        UartSendByte2();
    }    
}

main.c

#include "uart2.h"
#include "uart2_handle.h"
#include "timer2.h"

int main(void)
{	

    USART2Init(BAUD2);//初始化串口和配置波特率
    TIM2Init(10, 7200);//配置定时器配置1MS



	while (1)
    {

        UartDriver2();//串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用
     
    }
	
}

串口3工程包含的代码文件有如下几个文件
timer2.h

#ifndef _TIMER2_H
#define _TIMER2_H

#include "config.h"

void TIM2Init(u16 period, u16 prescaler);//中断处理函数放在stm32f10x_it.c文件

#endif

timer2.c

#include "timer2.h"

/* TIM2中断优先级配置函数, */
void NVIC_TIM2Enable(void)
{
    NVIC_InitTypeDef NVIC_initstructure;

    NVIC_initstructure.NVIC_IRQChannel = TIM2_IRQn;           //选择TIM2中断通道
    NVIC_initstructure.NVIC_IRQChannelCmd = ENABLE;           //使能中断通道
    NVIC_initstructure.NVIC_IRQChannelPreemptionPriority = 0; //设定抢占优先级为0
    NVIC_initstructure.NVIC_IRQChannelSubPriority = 0;        //设定响应优先级为0
    NVIC_Init(&NVIC_initstructure);
}

/* 定时器2初始化函数,period-计数周期,Prescaler-预分频值 */
void TIM2Init(u16 period, u16 prescaler)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);        //使能TIM2时钟
    TIM_TimeBaseStructure.TIM_Period = period-1;                //设定自动重装载计数值
    TIM_TimeBaseStructure.TIM_Prescaler = prescaler-1;          //设定预分频系数   计数时钟=定时器时钟/(分频系数+1)
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;                //基本定时器没有时钟分频功能,此项会被忽略
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置向上计数模式 基本定时器只有向上
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);             //初始化TIM2
    NVIC_TIM2Enable();                                          //初始化TIM2中断优先级
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);                 //清除中断标志位,否则启动中断会先进中断服务函数
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE );                 //使能TIM2中断
    TIM_Cmd(TIM2, ENABLE);                                      //使能TIM2定时器
}

uart3.h

#ifndef _UART3_H
#define _UART3_H
#include "config.h"

#define BAUD3 9600 //波特率宏定义
void USART3Init(u32 baud);//初始化串口和配置波特率


#endif

uart3.c

#include "uart3.h"


void USART3_IOInit(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;             //
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;       //
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     //
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;            //
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

void NVIC_USART3Enable(void)  
{
    NVIC_InitTypeDef NVIC_InitStructure;
    
    NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;         //
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //
    NVIC_Init(&NVIC_InitStructure);
}


void USART3Init(u32 baud)
{
    USART_InitTypeDef USART_InitStructure;
    
    USART3_IOInit();                                            
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);      
    USART_InitStructure.USART_BaudRate = baud;                  
    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_Tx|USART_Mode_Rx; 
    USART_Init(USART3, &USART_InitStructure);                     
    NVIC_USART3Enable();                          
    USART_ITConfig(USART3,USART_IT_RXNE, ENABLE); 
    USART_Cmd(USART3,ENABLE);                     
}

uart3_handle.h

#ifndef _UART3_HANDLE_H
#define _UART3_HANDLE_H
#include"config.h"


#define JIANGE_TIME3 30 //帧间隔时间宏定义


void UartWrite3(unsigned char *buf, unsigned char len);//串口数据写入,即串口发送函数
unsigned char UartRead3(unsigned char *buf, unsigned char len);//串口数据读取函数
void UartRxMonitor3(unsigned char ms);//串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔
void UartAction3(unsigned char *buf, unsigned char len);//串口动作函数,根据接收到的命令帧执行响应的动作
void UartDriver3(void);//串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用
void UartSendByte3(void);/* 从串口发送一字节数据,需在串口发送中断中调用 */
extern unsigned char cntRxd3;   //接收字节计数器
extern unsigned char bufRxd3[60];  //接收字节缓冲区

#endif

uart3_handle.c

#include "uart3_handle.h"

unsigned char flagFrame3=0;
unsigned char cntRxd3 = 0;   //接收字节计数器
unsigned char bufRxd3[60]={0};  //接收字节缓冲区
unsigned char bufTxd3[60]={0}; //数据发送缓冲区

int  bufTxdPosition3 = 0;   //缓冲区发送数据的最后位置
int  bufWritePosition3 = 0; //向缓冲区写入数据的最后位置

/* 串口数据写入,即串口发送函数,buf-待发送数据的指针,len-指定的发送长度 */
void UartWrite3(unsigned char *buf, unsigned char len)
{

    while (len--)   //循环发送所有字节
    {
        bufTxd3[bufWritePosition3] = *buf++;//待发送数据逐一复制到发送缓冲区
        bufWritePosition3++;//向缓冲区写入数据的最后位置
    }
    USART_ITConfig(USART3, USART_IT_TXE, ENABLE); //开启发送中断发送数据
}


void UartSendByte3(void)/* 从串口发送一字节数据,需在串口发送中断中调用 */
{
    if (bufTxdPosition3 != bufWritePosition3) //最后发送位置与写入位置不等,说明还有需要发送的数据
    {
        USART_SendData(USART3, bufTxd3[bufTxdPosition3]); //发出最后位置上的数据
        bufTxdPosition3++;          //至缓冲区结尾时归零
   
    }
    else                                    //最后发送位置与写入位置相等,说明写入的数据已发送完
    {
        bufTxdPosition3=0;
        bufWritePosition3=0;
        USART_ITConfig(USART3, USART_IT_TXE, DISABLE);    //关闭发送中断,终止本次发送
        
    }
}

/* 串口数据读取函数,buf-接收指针,len-指定的读取长度,返回值-实际读到的长度 */
unsigned char UartRead3(unsigned char *buf, unsigned char len)
{
    unsigned char i;
    
    if (len > cntRxd3)  //指定读取长度大于实际接收到的数据长度时,
    {                  //读取长度设置为实际接收到的数据长度
        len = cntRxd3;
    }
    for (i=0; i<len; i++)  //拷贝接收到的数据到接收指针上
    {
        *buf++ = bufRxd3[i];
    }
    cntRxd3 = 0;  //接收计数器清零
    
    return len;  //返回实际读取长度
}


void UartRxMonitor3(unsigned char ms)/* 串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔 */
{
    static unsigned char cntbkp = 0;
    static unsigned char idletmr = 0;

    if (cntRxd3 > 0)  //接收计数器大于零时,监控总线空闲时间
    {
        if (cntbkp != cntRxd3)  //接收计数器改变,即刚接收到数据时,清零空闲计时
        {
            cntbkp = cntRxd3;
            idletmr = 0;
        }
        else                   //接收计数器未改变,即总线空闲时,累积空闲时间
        {
            if (idletmr < JIANGE_TIME3)  //空闲计时小于30ms时,持续累加
            {
                idletmr += ms;
                if (idletmr >= JIANGE_TIME3)  //空闲时间达到30ms时,即判定为一帧接收完毕
                {
                    flagFrame3 = 1;  //设置帧接收完成标志
						 
                }
            }
        }
    }
    else
    {
        cntbkp = 0;
    }
}


/* 串口动作函数,根据接收到的命令帧执行响应的动作
   buf-接收到的命令帧指针,len-命令帧长度 */
void UartAction3(unsigned char *buf, unsigned char len)
{
    UartWrite3(buf,len);
   
}





/* 串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用 */
void UartDriver3()
{
    unsigned char len;
    unsigned char buf[60];

    if (flagFrame3) //有命令到达时,读取处理该命令
    {
        flagFrame3 = 0;
       
        len = UartRead3(buf, sizeof(buf)); //将接收到的命令读取到缓冲区中
        
        UartAction3(buf, len);  //传递数据帧,调用动作执行函数
		

    }
}



stm32f10x_it.c

#include "stm32f10x_it.h"
#include "uart3_handle.h"
void TIM2_IRQHandler(void)
{

    if (TIM_GetITStatus(TIM2, TIM_FLAG_Update) == SET) //检测是否为定时器溢出中断
    {
        TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update);  //清除中断标志位      
        
	
        UartRxMonitor3(1);/* 串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔 */
       
    }
}

void  USART3_IRQHandler(void)
{
   
    if(USART_GetITStatus(USART3,USART_IT_RXNE) == SET)  //检测接收中断标志位    
    {
      if (cntRxd3 < sizeof(bufRxd3)) //接收缓冲区尚未用完时,
       {                            //保存接收字节,并递增计数器

            bufRxd3[cntRxd3++] =USART_ReceiveData(USART3);  //读取接收到的数据

       }
    }
    if(USART_GetITStatus(USART3, USART_IT_TXE) == SET)  //检测发送中断标志位    
    {
        UartSendByte3();
    }    
}

main.c

#include "uart3.h"
#include "uart3_handle.h"
#include "timer2.h"

int main(void)
{	

 
    USART3Init(BAUD3);//初始化串口和配置波特率
    TIM2Init(10, 7200);



	while (1)
    {

        UartDriver3();//串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用
     
    }
	
}

串口4工程包含的代码文件有如下几个文件
timer2.h

#ifndef _TIMER2_H
#define _TIMER2_H

#include "config.h"

void TIM2Init(u16 period, u16 prescaler);//中断处理函数放在stm32f10x_it.c文件

#endif

timer2.c

#include "timer2.h"

/* TIM2中断优先级配置函数, */
void NVIC_TIM2Enable(void)
{
    NVIC_InitTypeDef NVIC_initstructure;

    NVIC_initstructure.NVIC_IRQChannel = TIM2_IRQn;           //选择TIM2中断通道
    NVIC_initstructure.NVIC_IRQChannelCmd = ENABLE;           //使能中断通道
    NVIC_initstructure.NVIC_IRQChannelPreemptionPriority = 0; //设定抢占优先级为0
    NVIC_initstructure.NVIC_IRQChannelSubPriority = 0;        //设定响应优先级为0
    NVIC_Init(&NVIC_initstructure);
}

/* 定时器2初始化函数,period-计数周期,Prescaler-预分频值 */
void TIM2Init(u16 period, u16 prescaler)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);        //使能TIM2时钟
    TIM_TimeBaseStructure.TIM_Period = period-1;                //设定自动重装载计数值
    TIM_TimeBaseStructure.TIM_Prescaler = prescaler-1;          //设定预分频系数   计数时钟=定时器时钟/(分频系数+1)
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;                //基本定时器没有时钟分频功能,此项会被忽略
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置向上计数模式 基本定时器只有向上
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);             //初始化TIM2
    NVIC_TIM2Enable();                                          //初始化TIM2中断优先级
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);                 //清除中断标志位,否则启动中断会先进中断服务函数
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE );                 //使能TIM2中断
    TIM_Cmd(TIM2, ENABLE);                                      //使能TIM2定时器
}

uart4.h

#ifndef _UART4_H
#define _UART4_H
#include "config.h"

#define BAUD4 9600  //波特率宏定义
void UART4Init(u32 baud);//初始化串口和配置波特率


#endif

uart4.c

#include "uart4.h"




/* UART4引脚初始化 */
void UART4_IOInit(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //使能GPIOC时钟
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;             //TXD引脚-C10
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;       //TXD设置为复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     //输出速率50MHz
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;             //RXD引脚-C11
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //RXD浮空输入
    GPIO_Init(GPIOC, &GPIO_InitStructure);
}
/* UART4中断优先级初始化 */
void NVIC_UART4Enable(void)  
{
    NVIC_InitTypeDef NVIC_InitStructure;
    
    NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;         //选择UART4中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //设置抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //设置响应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;          //使能通道
    NVIC_Init(&NVIC_InitStructure);
}

/* UART4模块初始化函数, baud-波特率 */
void UART4Init(u32 baud)
{
    USART_InitTypeDef USART_InitStructure;
    
    UART4_IOInit();                                            //UART4引脚初始化
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);      //使能时钟,USART1时钟在AP2上,其它4个串口在AP1上
    USART_InitStructure.USART_BaudRate = baud;                  //设置波特率为baud
    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_Tx|USART_Mode_Rx; //选择UART发送和接收模式
    USART_Init(UART4, &USART_InitStructure);                    //初始化UART4
    NVIC_UART4Enable();                          //UART4中断优先级初始化
    USART_ITConfig(UART4,USART_IT_RXNE, ENABLE); //开启串口接受中断
    USART_Cmd(UART4,ENABLE);                     //UART4
}



uart4_handle.h

#ifndef _UART4_HANDLE_H
#define _UART4_HANDLE_H
#include"config.h"


#define JIANGE_TIME4 30  //帧间隔时间宏定义


void UartWrite4(unsigned char *buf, unsigned char len);//串口数据写入,即串口发送函数
unsigned char UartRead4(unsigned char *buf, unsigned char len);//串口数据读取函数
void UartRxMonitor4(unsigned char ms);//串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔
void UartAction4(unsigned char *buf, unsigned char len);//串口动作函数,根据接收到的命令帧执行响应的动作
void UartDriver4(void);//串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用
void UartSendByte4(void);/* 从串口发送一字节数据,需在串口发送中断中调用 */
extern unsigned char cntRxd4;   //接收字节计数器
extern unsigned char bufRxd4[60];  //接收字节缓冲区

#endif

uart4_handle.c

#include "uart4_handle.h"

unsigned char flagFrame4=0;
unsigned char cntRxd4 = 0;   //接收字节计数器
unsigned char bufRxd4[60]={0};  //接收字节缓冲区
unsigned char bufTxd4[60]={0}; //数据发送缓冲区

int  bufTxdPosition4 = 0;   //缓冲区发送数据的最后位置
int  bufWritePosition4 = 0; //向缓冲区写入数据的最后位置

/* 串口数据写入,即串口发送函数,buf-待发送数据的指针,len-指定的发送长度 */
void UartWrite4(unsigned char *buf, unsigned char len)
{

    while (len--)   //循环发送所有字节
    {
        bufTxd4[bufWritePosition4] = *buf++;//待发送数据逐一复制到发送缓冲区
        bufWritePosition4++;//向缓冲区写入数据的最后位置
    }
    USART_ITConfig(UART4, USART_IT_TXE, ENABLE); //开启发送中断发送数据
}


void UartSendByte4(void)/* 从串口发送一字节数据,需在串口发送中断中调用 */
{
    if (bufTxdPosition4 != bufWritePosition4) //最后发送位置与写入位置不等,说明还有需要发送的数据
    {
        USART_SendData(UART4, bufTxd4[bufTxdPosition4]); //发出最后位置上的数据
        bufTxdPosition4++;          //至缓冲区结尾时归零
   
    }
    else                                    //最后发送位置与写入位置相等,说明写入的数据已发送完
    {
        bufTxdPosition4=0;
        bufWritePosition4=0;
        USART_ITConfig(UART4, USART_IT_TXE, DISABLE);    //关闭发送中断,终止本次发送
        
    }
}

/* 串口数据读取函数,buf-接收指针,len-指定的读取长度,返回值-实际读到的长度 */
unsigned char UartRead4(unsigned char *buf, unsigned char len)
{
    unsigned char i;
    
    if (len > cntRxd4)  //指定读取长度大于实际接收到的数据长度时,
    {                  //读取长度设置为实际接收到的数据长度
        len = cntRxd4;
    }
    for (i=0; i<len; i++)  //拷贝接收到的数据到接收指针上
    {
        *buf++ = bufRxd4[i];
    }
    cntRxd4 = 0;  //接收计数器清零
    
    return len;  //返回实际读取长度
}


void UartRxMonitor4(unsigned char ms)/* 串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔 */
{
    static unsigned char cntbkp = 0;
    static unsigned char idletmr = 0;

    if (cntRxd4 > 0)  //接收计数器大于零时,监控总线空闲时间
    {
        if (cntbkp != cntRxd4)  //接收计数器改变,即刚接收到数据时,清零空闲计时
        {
            cntbkp = cntRxd4;
            idletmr = 0;
        }
        else                   //接收计数器未改变,即总线空闲时,累积空闲时间
        {
            if (idletmr < JIANGE_TIME4)  //空闲计时小于30ms时,持续累加
            {
                idletmr += ms;
                if (idletmr >= JIANGE_TIME4)  //空闲时间达到30ms时,即判定为一帧接收完毕
                {
                    flagFrame4 = 1;  //设置帧接收完成标志
						 
                }
            }
        }
    }
    else
    {
        cntbkp = 0;
    }
}


/* 串口动作函数,根据接收到的命令帧执行响应的动作
   buf-接收到的命令帧指针,len-命令帧长度 */
void UartAction4(unsigned char *buf, unsigned char len)
{
    UartWrite4(buf,len);
   
}





/* 串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用 */
void UartDriver4()
{
    unsigned char len;
    unsigned char buf[60];

    if (flagFrame4) //有命令到达时,读取处理该命令
    {
        flagFrame4 = 0;
       
        len = UartRead4(buf, sizeof(buf)); //将接收到的命令读取到缓冲区中
        
        UartAction4(buf, len);  //传递数据帧,调用动作执行函数
		

    }
}



stm32f10x_it.c

#include "stm32f10x_it.h"
#include "uart4_handle.h"
void TIM2_IRQHandler(void)
{

    if (TIM_GetITStatus(TIM2, TIM_FLAG_Update) == SET) //检测是否为定时器溢出中断
    {
        TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update);  //清除中断标志位      
        
	
        UartRxMonitor4(1);/* 串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔 */
       
    }
}

void  UART4_IRQHandler(void)
{
   
    if(USART_GetITStatus(UART4,USART_IT_RXNE) == SET)  //检测接收中断标志位    
    {
      if (cntRxd4 < sizeof(bufRxd4)) //接收缓冲区尚未用完时,
       {                            //保存接收字节,并递增计数器

            bufRxd4[cntRxd4++] =USART_ReceiveData(UART4);  //读取接收到的数据

       }
    }
    if(USART_GetITStatus(UART4, USART_IT_TXE) == SET)  //检测发送中断标志位    
    {
        UartSendByte4();
    }    
}

main.c

#include "uart4.h"
#include "uart4_handle.h"
#include "timer2.h"

int main(void)
{	

 
    UART4Init(BAUD4);//初始化串口和配置波特率
    TIM2Init(10, 7200);//配置定时器定时1MS



	while (1)
    {

        UartDriver4();//串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用
     
    }
	
}

串口5工程包含的代码文件有如下几个文件
timer2.h

#ifndef _TIMER2_H
#define _TIMER2_H

#include "config.h"

void TIM2Init(u16 period, u16 prescaler);//中断处理函数放在stm32f10x_it.c文件

#endif

timer2.c

#include "timer2.h"

/* TIM2中断优先级配置函数, */
void NVIC_TIM2Enable(void)
{
    NVIC_InitTypeDef NVIC_initstructure;

    NVIC_initstructure.NVIC_IRQChannel = TIM2_IRQn;           //选择TIM2中断通道
    NVIC_initstructure.NVIC_IRQChannelCmd = ENABLE;           //使能中断通道
    NVIC_initstructure.NVIC_IRQChannelPreemptionPriority = 0; //设定抢占优先级为0
    NVIC_initstructure.NVIC_IRQChannelSubPriority = 0;        //设定响应优先级为0
    NVIC_Init(&NVIC_initstructure);
}

/* 定时器2初始化函数,period-计数周期,Prescaler-预分频值 */
void TIM2Init(u16 period, u16 prescaler)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);        //使能TIM2时钟
    TIM_TimeBaseStructure.TIM_Period = period-1;                //设定自动重装载计数值
    TIM_TimeBaseStructure.TIM_Prescaler = prescaler-1;          //设定预分频系数   计数时钟=定时器时钟/(分频系数+1)
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;                //基本定时器没有时钟分频功能,此项会被忽略
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置向上计数模式 基本定时器只有向上
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);             //初始化TIM2
    NVIC_TIM2Enable();                                          //初始化TIM2中断优先级
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);                 //清除中断标志位,否则启动中断会先进中断服务函数
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE );                 //使能TIM2中断
    TIM_Cmd(TIM2, ENABLE);                                      //使能TIM2定时器
}

uart5.h

#ifndef _UART5_H
#define _UART5_H
#include "config.h"

#define BAUD5 9600  //波特率宏定义
void UART5Init(u32 baud);//初始化串口和配置波特率


#endif

uart5.c

#include "uart5.h"




/* UART5引脚初始化 */
void UART5_IOInit(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //使能GPIOB时钟
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); //使能GPIOB时钟
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;             //TXD引脚-C12
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;       //TXD设置为复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     //输出速率50MHz
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;            //RXD引脚-D2
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //RXD浮空输入
    GPIO_Init(GPIOD, &GPIO_InitStructure);
}
/* UART5中断优先级初始化 */
void NVIC_UART5Enable(void)  
{
    NVIC_InitTypeDef NVIC_InitStructure;
    
    NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn;         //选择USART5中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //设置抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //设置响应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //使能通道
    NVIC_Init(&NVIC_InitStructure);
}

/* UART5模块初始化函数, baud-波特率 */
void UART5Init(u32 baud)
{
    USART_InitTypeDef USART_InitStructure;
    
    UART5_IOInit();                                            //UART5引脚初始化
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);      //使能时钟,USART1时钟在AP2上,其它4个串口在AP1上
    USART_InitStructure.USART_BaudRate = baud;                  //设置波特率为baud
    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_Tx|USART_Mode_Rx; //选择USART发送和接收模式
    USART_Init(UART5, &USART_InitStructure);                     //初始化UART5
    NVIC_UART5Enable();                          //UART5中断优先级初始化
    USART_ITConfig(UART5,USART_IT_RXNE, ENABLE); //开启串口接受中断
    USART_Cmd(UART5,ENABLE);                     //使能UART5
}

uart5_handle.h

#ifndef _UART5_HANDLE_H
#define _UART5_HANDLE_H
#include"config.h"


#define JIANGE_TIME5 30//帧间隔时间宏定义


void UartWrite5(unsigned char *buf, unsigned char len);//串口数据写入,即串口发送函数
unsigned char UartRead5(unsigned char *buf, unsigned char len);//串口数据读取函数
void UartRxMonitor5(unsigned char ms);//串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔
void UartAction5(unsigned char *buf, unsigned char len);//串口动作函数,根据接收到的命令帧执行响应的动作
void UartDriver5(void);//串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用
void UartSendByte5(void);/* 从串口发送一字节数据,需在串口发送中断中调用 */
extern unsigned char cntRxd5;   //接收字节计数器
extern unsigned char bufRxd5[60];  //接收字节缓冲区

#endif

uart5_handle.c

#include "uart5_handle.h"

unsigned char flagFrame5=0;
unsigned char cntRxd5 = 0;   //接收字节计数器
unsigned char bufRxd5[60]={0};  //接收字节缓冲区
unsigned char bufTxd5[60]={0}; //数据发送缓冲区

int  bufTxdPosition5 = 0;   //缓冲区发送数据的最后位置
int  bufWritePosition5 = 0; //向缓冲区写入数据的最后位置

/* 串口数据写入,即串口发送函数,buf-待发送数据的指针,len-指定的发送长度 */
void UartWrite5(unsigned char *buf, unsigned char len)
{

    while (len--)   //循环发送所有字节
    {
        bufTxd5[bufWritePosition5] = *buf++;//待发送数据逐一复制到发送缓冲区
        bufWritePosition5++;//向缓冲区写入数据的最后位置
    }
    USART_ITConfig(UART5, USART_IT_TXE, ENABLE); //开启发送中断发送数据
}


void UartSendByte5(void)/* 从串口发送一字节数据,需在串口发送中断中调用 */
{
    if (bufTxdPosition5 != bufWritePosition5) //最后发送位置与写入位置不等,说明还有需要发送的数据
    {
        USART_SendData(UART5, bufTxd5[bufTxdPosition5]); //发出最后位置上的数据
        bufTxdPosition5++;          //至缓冲区结尾时归零
   
    }
    else                                    //最后发送位置与写入位置相等,说明写入的数据已发送完
    {
        bufTxdPosition5=0;
        bufWritePosition5=0;
        USART_ITConfig(UART5, USART_IT_TXE, DISABLE);    //关闭发送中断,终止本次发送
        
    }
}

/* 串口数据读取函数,buf-接收指针,len-指定的读取长度,返回值-实际读到的长度 */
unsigned char UartRead5(unsigned char *buf, unsigned char len)
{
    unsigned char i;
    
    if (len > cntRxd5)  //指定读取长度大于实际接收到的数据长度时,
    {                  //读取长度设置为实际接收到的数据长度
        len = cntRxd5;
    }
    for (i=0; i<len; i++)  //拷贝接收到的数据到接收指针上
    {
        *buf++ = bufRxd5[i];
    }
    cntRxd5 = 0;  //接收计数器清零
    
    return len;  //返回实际读取长度
}


void UartRxMonitor5(unsigned char ms)/* 串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔 */
{
    static unsigned char cntbkp = 0;
    static unsigned char idletmr = 0;

    if (cntRxd5 > 0)  //接收计数器大于零时,监控总线空闲时间
    {
        if (cntbkp != cntRxd5)  //接收计数器改变,即刚接收到数据时,清零空闲计时
        {
            cntbkp = cntRxd5;
            idletmr = 0;
        }
        else                   //接收计数器未改变,即总线空闲时,累积空闲时间
        {
            if (idletmr < JIANGE_TIME5)  //空闲计时小于30ms时,持续累加
            {
                idletmr += ms;
                if (idletmr >= JIANGE_TIME5)  //空闲时间达到30ms时,即判定为一帧接收完毕
                {
                    flagFrame5 = 1;  //设置帧接收完成标志
						 
                }
            }
        }
    }
    else
    {
        cntbkp = 0;
    }
}


/* 串口动作函数,根据接收到的命令帧执行响应的动作
   buf-接收到的命令帧指针,len-命令帧长度 */
void UartAction5(unsigned char *buf, unsigned char len)
{
    UartWrite5(buf,len);
   
}





/* 串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用 */
void UartDriver5()
{
    unsigned char len;
    unsigned char buf[60];

    if (flagFrame5) //有命令到达时,读取处理该命令
    {
        flagFrame5 = 0;
       
        len = UartRead5(buf, sizeof(buf)); //将接收到的命令读取到缓冲区中
        
        UartAction5(buf, len);  //传递数据帧,调用动作执行函数
		

    }
}




stm32f10x_it.c

#include "stm32f10x_it.h"
#include "uart5_handle.h"
void TIM2_IRQHandler(void)
{

    if (TIM_GetITStatus(TIM2, TIM_FLAG_Update) == SET) //检测是否为定时器溢出中断
    {
        TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update);  //清除中断标志位      
        
	
        UartRxMonitor5(1);/* 串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔 */
       
    }
}

void  UART5_IRQHandler(void)
{
   
    if(USART_GetITStatus(UART5,USART_IT_RXNE) == SET)  //检测接收中断标志位    
    {
      if (cntRxd5 < sizeof(bufRxd5)) //接收缓冲区尚未用完时,
       {                            //保存接收字节,并递增计数器

            bufRxd5[cntRxd5++] =USART_ReceiveData(UART5);  //读取接收到的数据

       }
    }
    if(USART_GetITStatus(UART5, USART_IT_TXE) == SET)  //检测发送中断标志位    
    {
        UartSendByte5();
    }    
}

main.c

#include "uart5.h"
#include "uart5_handle.h"
#include "timer2.h"


int main(void)
{	

 
    UART5Init(BAUD5);//初始化串口和配置波特率
    TIM2Init(10, 7200);



	while (1)
    {

        UartDriver5();//串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用
     
    }
	
}

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
STM32中,串口接收多个字节的方法可以使用中断或DMA方式实现。 1. 中断方式: 在中断服务函数中,通过判断接收缓冲区是否有足够的字节数来决定是否继续接收。例如,如果要接收10个字节,可以在串口接收中断服务函数中设置一个计数器,每次接收到一个字节就将计数器加1,当计数器达到10时,表示已经接收到了10个字节,可以将数据处理。 2. DMA方式: 使用DMA方式可以实现数据的无缝传输。首先需要配置DMA通道和串口接收缓冲区,然后启动DMA传输。当DMA传输完成后,通过中断或者轮询的方式进行数据处理。 以下是一个简单的示例代码,演示了如何使用中断方式接收多个字节: ``` #define BUFFER_SIZE 10 uint8_t rxBuffer[BUFFER_SIZE]; uint8_t rxCount = 0; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (rxCount < BUFFER_SIZE) { rxBuffer[rxCount++] = huart->Instance->DR; } if (rxCount == BUFFER_SIZE) { // 数据处理 // ... } } int main(void) { HAL_UART_Receive_IT(&huart1, &rxBuffer[0], 1); // 启动接收中断 while (1) {} } ``` 在上面的代码中,`HAL_UART_RxCpltCallback()`函数是UART接收中断服务函数。每次接收到一个字节,函数会将其存储在`rxBuffer`数组中,并将`rxCount`计数器加1。当`rxCount`等于`BUFFER_SIZE`时,表示已经接收到了足够的字节数,可以进行数据处理。在`main()`函数中,调用`HAL_UART_Receive_IT()`启动接收中断。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白q_5793545

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值