独闷闷网

 找回密码
 立即注册
搜索
查看: 6812|回复: 2
打印 上一主题 下一主题
收起左侧

[原创] 基于STM8的模拟串口接收与发送

[复制链接]
跳转到指定楼层
楼主
发表于 2015-1-1 15:34:37 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本帖最后由 电子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位推挽输出高电平
  1. #define Uart_RXD_Init()                       GPIO_Init(GPIOD,GPIO_PIN_6,GPIO_MODE_IN_PU_NO_IT)
  2. #define Uart_RXD_Status()                  GPIO_ReadInputPin(GPIOD,GPIO_PIN_6)

  3. #define Uart_TXD_Init()                        GPIO_Init(GPIOD,GPIO_PIN_5,GPIO_MODE_OUT_PP_HIGH_FAST)
  4. #define Uart_TXD_Out_HIGH()             GPIO_WriteHigh(GPIOD,GPIO_PIN_5)
  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、接收函数
  1. static void Uart_Rx_Byte(void)
  2. {
  3.         static uint8_t RxBitNum;        //接收位计数
  4.         static uint8_t OverTime;         //接收超时计时器
  5.         static uint8_t RxByteBuff;         //一字节数据接收缓存

  6.         if(1 == Uart_RXD_Status())
  7.         {
  8.                 OverTime++;
  9.         }
  10.         else
  11.         {
  12.                 OverTime = 0;
  13.         }

  14.         if(OverTime > 44)
  15.         {
  16.                 OverTime = 0;
  17.                 RxByteIndex = 0;
  18.                 RxBitNum = 0;
  19.         }

  20.         if((1 == Uart_RXD_Status()) && (0 == RxBitNum))
  21.         {
  22.                 RxSampFreq = 0;
  23.         }
  24.         else
  25.         {
  26.                 RxSampFreq++;
  27.         }

  28.         if(1 == RxSampFreq)
  29.         {
  30.                 if(0 == RxBitNum)
  31.                 {
  32.                         if(0 == Uart_RXD_Status())
  33.                         {
  34.                                 RxByteBuff = 0;
  35.                                 RxBitNum++;
  36.                         }
  37.                 }
  38.                 else if((RxBitNum > 0) && (RxBitNum < 9))
  39.                 {
  40.                         if(1 == Uart_RXD_Status())
  41.                         {
  42.                                 RxByteBuff = RxByteBuff | (1 << (RxBitNum - 1));
  43.                         }
  44.                         RxBitNum++;
  45.                 }
  46.                 else if(9 == RxBitNum)
  47.                 {
  48.                         if(1 == Uart_RXD_Status())
  49.                         {
  50.                                 RxBitNum = 0;
  51.                                 if(0x0d != RxByteBuff && 0x0a != RxByteBuff)
  52.                                 {
  53.                                         UartRxBuff[RxByteIndex] = RxByteBuff;
  54.                                         RxByteIndex++;
  55.                                         if(RxByteIndex > 63)
  56.                                         {
  57.                                                 RxByteIndex = 0;
  58.                                         }
  59.                                 }
  60.                                 else
  61.                                 {
  62.                                         TxXKCnt = RxByteIndex;
  63.                                         RxByteIndex = 0;
  64.                                         flag_rxd_finish = 1;
  65.                                 }
  66.                         }
  67.                 }
  68.                 else
  69.                 {
  70.                         RxBitNum = 0;
  71.                 }
  72.         }
  73.         else if(RxSampFreq > 3)
  74.         {
  75.                 RxSampFreq = 0;
  76.         }
  77. }
复制代码
步骤5、发送函数
  1. static void Uart_Tx_Byte(void)
  2. {
  3.         static bool SendFinish = 1;        //发送完成标志
  4.         static u8 TxSampFreq = 0;                //发送计数        采样4次
  5.         static u8 BitNum = 0;                        //位计数
  6.         static u8 ByteLock;                         //发送字节锁定(防止在发送途中 发送数字被改变)
  7.         static u8 TxIndex = 0;                        //当前发送索引

  8.         if(SendFinish)
  9.     {
  10.        SendFinish = 0;
  11.        RxSampFreq = 0;
  12.        BitNum = 0;

  13.        if(TxIndex < TxXKCnt)        //控制发送的字节
  14.        {
  15.           ByteLock = UartTxBuff[TxIndex];
  16.           TxIndex++;
  17.           RxByteIndex = 0;
  18.        }
  19.        else if(TxIndex == TxXKCnt)
  20.        {
  21.           ByteLock = '\n';
  22.           TxIndex++;
  23.           RxByteIndex = 0;
  24.        }
  25.        else
  26.        {
  27.           flag_rxd_txd = 1;
  28.           SendFinish = 0;
  29.           TxIndex = 0;
  30.        }
  31.     }

  32.     if(++TxSampFreq > 3)
  33.     {
  34.         if(BitNum == 0)                             //起始位
  35.         {
  36.             Uart_TXD_Out_LOW();
  37.             BitNum++;
  38.         }
  39.         else if((BitNum >0) && (BitNum < 9))        //数据位
  40.         {
  41.             if(0x01 & (ByteLock >> (BitNum-1)))     //先发低位
  42.             {
  43.                 Uart_TXD_Out_HIGH();
  44.             }
  45.             else
  46.             {
  47.                 Uart_TXD_Out_LOW();
  48.             }
  49.             BitNum++;
  50.         }
  51.         else if(BitNum == 9)                        //结束码
  52.         {
  53.             Uart_TXD_Out_HIGH();
  54.             SendFinish = 1;
  55.             BitNum = 0;
  56.         }
  57.         TxSampFreq = 0;
  58.     }
  59. }
复制代码



乐于分享,勇于质疑!
沙发
发表于 2015-1-1 18:01:44 | 只看该作者
非常漂亮。我仔细看了这个思路,利用定时器控制时序应该比delay延时更加精确,果断加精。
乐于分享,勇于质疑!
板凳
 楼主| 发表于 2015-1-1 18:06:49 | 只看该作者
jianhong_wu 发表于 2015-1-1 18:01
非常漂亮。我仔细看了这个思路,利用定时器控制时序应该比delay延时更加精确,果断加精。

基本我对delay产生非常大的厌恶感,如非必要,绝对不用,我的裸编程思想都是:前后台
乐于分享,勇于质疑!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|独闷闷网 ( 粤ICP备12007667号-2 )

GMT+8, 2024-11-29 18:20 , Processed in 0.169180 second(s), 20 queries .

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