电子Inc 发表于 2015-1-1 15:34:37

基于STM8的模拟串口接收与发送

本帖最后由 电子Inc 于 2015-1-1 15:45 编辑

       前言:在我们日常生活中,为了减少成本,在通信中往往使用串口通信,而我们使用到的单片机,也集成了USART这一模块,但是, 当需要到多个串口工作时,这单片机集成的1个或者两个串口
却远远不够需求,所以,我们得使用模拟得手段来给单片机实现多个串口。
       这里,我们使用STM8来完成这一实验:

1、串口通信的格式:起始位(1)------数据位(8位/7位)-------校验位(0/1)--------停止位(1)
      因为我们很少用到校验位,所以,校验位可有可无
2、波特率, 意思是每秒发送多少个bit,单位是 bit/s, 我们常用bps来表示, 例如 9600bps, 4800bps, 2400bps
3、采样频率, 为了保持精度,减少接收数据和发送数据的误差,我们把采样次数增多,利用多次采样次数中的固定位置采样

思路:以STM8位基准,我们设定此时的波特路为9600bps,利用定时器中断产生时间间隔, 1秒传送9600bit相当于 1bit需要104us,而我们这里采样次数取4次,定时时间是26us
          PS:因为STM8使用内部晶振,难免出现误差,所以在现实使用中,如果使用26us间隔读取,往往出现数据错误,在实际应用中,我采用24~25us的间隔,数据接收发送正确

实验工具:STM8S103FP6最小系统版, ST-linkV2, PL2303转串口模块

步骤1、算出定时初值, STM8内部晶振为16M, 采用8分频后震荡周期 =8/16 = 0.5us,所以发送或接受以为数据的采样定时器初值应为48~52;
下面为定时器初始化代码:void Tim2_Init(void)
{
        TIM2_DeInit();
        TIM2_TimeBaseInit(TIM2_PRESCALER_8, 48);
        TIM2_ClearFlag(TIM2_FLAG_UPDATE);
        TIM2_ITConfig(TIM2_IT_UPDATE, ENABLE);
        TIM2_Cmd(ENABLE);
}

步骤2、RXD和TXD初始化,RXD为上拉输入,TXD位推挽输出高电平
#define Uart_RXD_Init()                     GPIO_Init(GPIOD,GPIO_PIN_6,GPIO_MODE_IN_PU_NO_IT)
#define Uart_RXD_Status()                  GPIO_ReadInputPin(GPIOD,GPIO_PIN_6)

#define Uart_TXD_Init()                        GPIO_Init(GPIOD,GPIO_PIN_5,GPIO_MODE_OUT_PP_HIGH_FAST)
#define Uart_TXD_Out_HIGH()             GPIO_WriteHigh(GPIOD,GPIO_PIN_5)
#define Uart_TXD_Out_LOW()             GPIO_WriteLow(GPIOD,GPIO_PIN_5)步骤3、中断调用函数
void Uart_Interrupt(void)
{
        uint8_t i;

        if(1 == flag_rxd_finish)
        {
                flag_rxd_finish = 0;
                flag_rxd_txd = 0;
                for(i = 0;i < TxXKCnt; i++)
                {
                        UartTxBuff = UartRxBuff;
                }
        }

        if(1 == flag_rxd_txd)         // 为1,接收
        {
                Uart_Rx_Byte();
        }
        else                                        // 为0,发送
        {
                Uart_Tx_Byte();
        }
}


步骤4、接收函数
static void Uart_Rx_Byte(void)
{
      static uint8_t RxBitNum;      //接收位计数
      static uint8_t OverTime;         //接收超时计时器
      static uint8_t RxByteBuff;         //一字节数据接收缓存

      if(1 == Uart_RXD_Status())
      {
                OverTime++;
      }
      else
      {
                OverTime = 0;
      }

      if(OverTime > 44)
      {
                OverTime = 0;
                RxByteIndex = 0;
                RxBitNum = 0;
      }

      if((1 == Uart_RXD_Status()) && (0 == RxBitNum))
      {
                RxSampFreq = 0;
      }
      else
      {
                RxSampFreq++;
      }

      if(1 == RxSampFreq)
      {
                if(0 == RxBitNum)
                {
                        if(0 == Uart_RXD_Status())
                        {
                              RxByteBuff = 0;
                              RxBitNum++;
                        }
                }
                else if((RxBitNum > 0) && (RxBitNum < 9))
                {
                        if(1 == Uart_RXD_Status())
                        {
                              RxByteBuff = RxByteBuff | (1 << (RxBitNum - 1));
                        }
                        RxBitNum++;
                }
                else if(9 == RxBitNum)
                {
                        if(1 == Uart_RXD_Status())
                        {
                              RxBitNum = 0;
                              if(0x0d != RxByteBuff && 0x0a != RxByteBuff)
                              {
                                        UartRxBuff = RxByteBuff;
                                        RxByteIndex++;
                                        if(RxByteIndex > 63)
                                        {
                                                RxByteIndex = 0;
                                        }
                              }
                              else
                              {
                                        TxXKCnt = RxByteIndex;
                                        RxByteIndex = 0;
                                        flag_rxd_finish = 1;
                              }
                        }
                }
                else
                {
                        RxBitNum = 0;
                }
      }
      else if(RxSampFreq > 3)
      {
                RxSampFreq = 0;
      }
}步骤5、发送函数
static void Uart_Tx_Byte(void)
{
      static bool SendFinish = 1;      //发送完成标志
      static u8 TxSampFreq = 0;                //发送计数      采样4次
      static u8 BitNum = 0;                        //位计数
      static u8 ByteLock;                         //发送字节锁定(防止在发送途中 发送数字被改变)
      static u8 TxIndex = 0;                        //当前发送索引

      if(SendFinish)
    {
       SendFinish = 0;
       RxSampFreq = 0;
       BitNum = 0;

       if(TxIndex < TxXKCnt)      //控制发送的字节
       {
          ByteLock = UartTxBuff;
          TxIndex++;
          RxByteIndex = 0;
       }
       else if(TxIndex == TxXKCnt)
       {
          ByteLock = '\n';
          TxIndex++;
          RxByteIndex = 0;
       }
       else
       {
          flag_rxd_txd = 1;
          SendFinish = 0;
          TxIndex = 0;
       }
    }

    if(++TxSampFreq > 3)
    {
      if(BitNum == 0)                           //起始位
      {
            Uart_TXD_Out_LOW();
            BitNum++;
      }
      else if((BitNum >0) && (BitNum < 9))      //数据位
      {
            if(0x01 & (ByteLock >> (BitNum-1)))   //先发低位
            {
                Uart_TXD_Out_HIGH();
            }
            else
            {
                Uart_TXD_Out_LOW();
            }
            BitNum++;
      }
      else if(BitNum == 9)                        //结束码
      {
            Uart_TXD_Out_HIGH();
            SendFinish = 1;
            BitNum = 0;
      }
      TxSampFreq = 0;
    }
}


jianhong_wu 发表于 2015-1-1 18:01:44

非常漂亮。我仔细看了这个思路,利用定时器控制时序应该比delay延时更加精确,果断加精。

电子Inc 发表于 2015-1-1 18:06:49

jianhong_wu 发表于 2015-1-1 18:01
非常漂亮。我仔细看了这个思路,利用定时器控制时序应该比delay延时更加精确,果断加精。

基本我对delay产生非常大的厌恶感,如非必要,绝对不用,我的裸编程思想都是:前后台
页: [1]
查看完整版本: 基于STM8的模拟串口接收与发送