[STM32F1] 采用普通IO模拟串口发送和接收,支持10路串口

[复制链接]
198|0
ljxh401 发表于 2025-11-18 21:59 | 显示全部楼层 |阅读模式
, , , ,
本帖最后由 ljxh401 于 2025-11-19 17:08 编辑

#申请原创#
/******************************************************************************

******************************************************************************
  文 件 名   : MoniUartX.c
  版 本 号   : 初稿
  作    者   : ljxh401
  生成日期   : 2025年11月18日
  最近修改   :
  功能描述   : 模拟串口的接收和发送,波特率4800,将时间中断频率设置为波特率的3倍,为了更准确的截取同步信号
                    尽量精简串口中断的函数,每一路串口都带缓存环
  函数列表   :
  修改历史   :
  1.日    期   : 2025年11月18日
    作    者   : ljxh401
    修改内容   : 创建文件

******************************************************************************/

头文件
#ifndef __MONI_UARTX_H__
#define __MONI_UARTX_H__
typedef struct{
        INT32U *pinRec;
        INT32U *pinSnd;
        INT8U zeroCnt;
        INT8U recbit;
        INT8U reccach;
        INT8U rb,re;
        INT8U rec[16];
        INT8U sndbit;
        INT8U sndCach;
        INT8U sb,se;
        INT8U snd[32];                                //发送显示数据
}S_MnCom;

void MoniUartInit(void);
void MoniUartSendData(INT8U id,INT8U *buf,INT8U len);
INT8U MoniUartGetData(INT8U id,INT8U *err);

#endif


/*----------------------------------------------*
* 包含头文件                                   *
*----------------------------------------------*/
#include "includes.h"
/*----------------------------------------------*
* 宏定义                                       *
*----------------------------------------------*/
#define ComNum        10
#define Boud              9600
#define Mbit(_ADDR,_Bit) (0x42000000+((unsigned long)&(_ADDR)-0x40000000)*32 + _Bit*4)

/*----------------------------------------------*
* 外部变量说明                                 *
*----------------------------------------------*/

/*----------------------------------------------*
* 外部函数原型说明                             *
*----------------------------------------------*/

/*----------------------------------------------*
* 内部函数原型说明                             *
*----------------------------------------------*/

/*----------------------------------------------*
* 全局变量                                     *
*----------------------------------------------*/

/*----------------------------------------------*
* 模块级变量                                   *
*----------------------------------------------*/
S_MnCom cd[ComNum];                        //记录10个串口的接收数据

/*----------------------------------------------*
* 常量定义                                     *
*----------------------------------------------*/
const INT32U PinTab[]={
        Mbit(GPIOB->ODR,1),Mbit(GPIOB->IDR,10),
        Mbit(GPIOB->ODR,11),Mbit(GPIOB->IDR,12),
        Mbit(GPIOB->ODR,13),Mbit(GPIOB->IDR,14),
        Mbit(GPIOB->ODR,15),Mbit(GPIOA->IDR,8),
        Mbit(GPIOA->ODR,11),Mbit(GPIOA->IDR,12),
        Mbit(GPIOA->ODR,13),Mbit(GPIOA->IDR,14),
        Mbit(GPIOA->ODR,15),Mbit(GPIOB->IDR,3),
        Mbit(GPIOB->ODR,4),Mbit(GPIOB->IDR,5),
        Mbit(GPIOB->ODR,6),Mbit(GPIOB->IDR,7),
        Mbit(GPIOB->ODR,8),Mbit(GPIOB->IDR,9),
};


/*****************************************************************************
函 数 名  : MoniUartInit
功能描述  : 模拟串口的初始化
输入参数  : void  
输出参数  : 无
返 回 值  :
调用函数  :
被调函数  :

修改历史      :
  1.日    期   : 2025年11月18日
    作    者   : ljxh401
    修改内容   : 新生成函数

*****************************************************************************/
void MoniUartInit(void)
{
        INT8U i;
        NormalPA131415PB3PB4();
        //设置输出
        SetPinState(GPIOA, GPIO_Pin_11|GPIO_Pin_13|GPIO_Pin_15, GPIO_Mode_Out_PP);
        SetPinState(GPIOB, GPIO_Pin_11|GPIO_Pin_13|GPIO_Pin_15|GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_6|GPIO_Pin_8, GPIO_Mode_Out_PP);
        //设置输入
        SetPinState(GPIOB, GPIO_Pin_10|GPIO_Pin_12|GPIO_Pin_14|GPIO_Pin_3|GPIO_Pin_5|GPIO_Pin_7|GPIO_Pin_9, GPIO_Mode_IPU);
        SetPinState(GPIOA, GPIO_Pin_8|GPIO_Pin_12|GPIO_Pin_14, GPIO_Mode_IPU);

        for(i=0;i<ComNum;i++)
        {
                cd.pinSnd=(INT32U*)PinTab[i*2+0];
                cd.pinRec=(INT32U*)PinTab[i*2+1];
                cd.sndbit=10;
                cd.recbit=28;
                *cd.pinSnd=1;
        }
        
        Tim1_PWM_Init(
Boud*3,2,0,1);
}


/*****************************************************************************
函 数 名  : MoniUartSendData
功能描述  : 将数据发送到缓存里面
输入参数  : INT8U id   
             INT8U *buf  
             INT8U len   
输出参数  : 无
返 回 值  :
调用函数  :
被调函数  :

修改历史      :
  1.日    期   : 2025年11月18日
    作    者   : ljxh401
    修改内容   : 新生成函数

*****************************************************************************/
void MoniUartSendData(INT8U id,INT8U *buf,INT8U len)
{
        INT8U cnt;
        cnt=cd[id].se;
        do{
                cd[id].snd[cnt]=*buf++;
                if(++cnt>=sizeof(cd[0].snd))        cnt=0;
        }while(--len>0);
        cd[id].se=cnt;
}

/*****************************************************************************
函 数 名  : MoniUartGetData
功能描述  : 将数据发送到缓存里面
输入参数  : INT8U id   
             INT8U *buf  
             INT8U len   
输出参数  : 无
返 回 值  :
调用函数  :
被调函数  :

修改历史      :
  1.日    期   : 2025年11月18日
    作    者   : ljxh401
    修改内容   : 新生成函数

*****************************************************************************/
INT8U MoniUartGetData(INT8U id,INT8U *err)
{
        INT8U d;
        if(cd[id].rb!=cd[id].re)
        {
                *err=0;
                d=cd[id].rec[cd[id].rb];
                if(++cd[id].rb>=sizeof(cd[0].rec))        cd[id].rb=0;
        }
        else *err=1;
        return d;
}

/*****************************************************************************
函 数 名  : CheckRec
功能描述  : 串口接收,检测串口IO的输入数据
输入参数  : void  
输出参数  : 无
返 回 值  :
调用函数  :
被调函数  :

修改历史      :
  1.日    期   : 2025年11月18日
    作    者   : ljxh401
    修改内容   : 新生成函数

*****************************************************************************/
void CheckRec(void)
{
        INT8U i;
        for(i=0;i<ComNum;i++)
        {
                if(cd.recbit==28)
                {
                        if(*cd.pinRec==0)
                        {
                                if(++cd.zeroCnt>=2)                //连线两个0,确定起始帧,然后从第二个0 作为采集帧
                                {
                                        cd.zeroCnt=0;
                                        cd.reccach=0;
                                        cd.recbit=0;
                                }
                                else ++cd.zeroCnt;
                        }
                        else cd.zeroCnt=0;
                }
                else{
                        if((cd.recbit%3)==2)                        //在中间采样,这样防止错误率
                        {
                                if(*cd.pinRec) cd.reccach|=BitTab[cd.recbit/3];
                        }
                        if(++cd.recbit==28)                        //最后一帧,不做验证后面的28-30 的高电平
                        {
                                cd.rec[cd.re]=cd.reccach;
                                if(++cd.re>=sizeof(cd[0].rec))        cd.re=0;
                        }
                }
        }
}

/*****************************************************************************
函 数 名  : SendBitData
功能描述  : 发送串口数据 的模拟IO
输入参数  : INT8U i  
输出参数  : 无
返 回 值  :
调用函数  :
被调函数  :

修改历史      :
  1.日    期   : 2025年11月18日
    作    者   : ljxh401
    修改内容   : 新生成函数

*****************************************************************************/
void SendBitData(INT8U i)
{
        for(;i<ComNum;i+=3)                                                                                
        {
                if(cd.sndbit<10)
                {
                        if(cd.sndbit==0)                *cd.pinSnd=0;                //启动
                        else if(cd.sndbit<9)                                                        //数据
                        {
                                *cd.pinSnd=(cd.sndCach&1);
                                cd.sndCach>>=1;
                        }
                        else *cd.pinSnd=1;                                                        //结束
                        ++cd.sndbit;
                }
                else if(cd.sb!=cd.se)
                {
                        cd.sndCach=cd.snd[cd.sb];
                        if(++cd.sb>=sizeof(cd[0].snd))        cd.sb=0;
                        cd.sndbit=0;
                }
        }
}

/*****************************************************************************
函 数 名  : TIM1_UP_IRQHandler
功能描述  : 定时器1中断
输入参数  : void  
输出参数  : 无
返 回 值  :
调用函数  :
被调函数  :

修改历史      :
  1.日    期   : 2025年11月18日
    作    者   : ljxh401
    修改内容   : 新生成函数

*****************************************************************************/
void TIM1_UP_IRQHandler (void)
{
        static INT8U cnt=0;
        TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
        CheckRec();
        if(++cnt>=3)        cnt=0;                                //均匀每次时间中断的工作量
        SendBitData(cnt);
}




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

本版积分规则

55

主题

246

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部