stm8s 105 tim4虚拟串口

这个也是想了很久了,今天终于能实现了

记录一下

首先说一下基础知识

串口通讯:

串口通信原理和模拟串口发送数据的原理

标准串口数据格式为:起始位(1bit)+数据位(8bit)+校验位(1bit)+停止位(1bit)。其中起始位为低电平,停止位为高电平。

串口通讯需要设置波特率和检查COM口。 网上找到好多,都是使用2,感觉太浪费了。我这里改成4

思路是这样的,我们使用定时器TIM2来定时,每隔一段时间发送一个位,从而实现模拟串口发送数据。

计算9600波特率 对应的ARR自动装载的值

不要校验位,因此共有10个位的数据。

我以stm8中9600bit/s的波特率计算的过程为例(1秒钟传输9600位)。

可以计算出传输1位所需要的时间 T1 = 1/9600 约为104us。

stm8 内部晶振频率为16M,我采用16分频也就是1M,故MCU震荡周期为 1/1M = 1us。

由上面的计算我们可以知道要发送一位数据,定时器中定时的自动装载的值应设为为 104/1 =104。

实现过程
void main(void)
{
  All_Config();   // 各种初始化
  enableInterrupts();     //  使能中断
  while (1)
  {
  SimUART_TxByte( 0xF0 );
  Delay_ms(1000);   // 延时 1ms
  }
  
  
  
}

这里发送了 一个 F0,相对来说 4高4低,方便看波形,不敢相信,我自己舍不得买一个示波器,伤心啊。

先看初始化函数
void All_Config( void )
{
  CLK_HSICmd(ENABLE);   //使用内部高速晶振
  CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);      // 设置时钟分频为1
  GPIO_Init(GPIOA, GPIO_PIN_5, GPIO_MODE_OUT_PP_LOW_FAST);    // 初始化 虚拟串口IO输出管脚 TX
  TIM4_Init();    // 计时器 4 初始化
}

GPIO_Init(GPIOA, GPIO_PIN_5, GPIO_MODE_OUT_PP_LOW_FAST); 我使用了 A5 作为发送端口,这里可以改,也可以做个 宏定义。

然后就是初始化 定时器4

来看一下怎么初始化

/*其中,TIM4_DeInit() 函数用于将定时器4的所有寄存器恢复到默认值,
以确保定时器4处于初始状态。TIM4_Cmd() 函数用于使能定时器4,使其开始计数。
TIM4_TimeBaseInit() 函数用于配置定时器4的时基,其中 TIM4_PRESCALER_16 表示分频系数为16,
0x68 表示自动重载值为0x68,即当计数器计数到0x68时,定时器4会自动重新计数。
最后,TIM4->CNTR = 0; 语句将定时器4的计数器清零,以确保定时器4从0开始计数。*/

void TIM4_Init()
{
    TIM4_DeInit(); // 复位定时器4
    TIM4_Cmd(ENABLE); // 使能定时器4
    TIM4_TimeBaseInit(TIM4_PRESCALER_16, 0x68); // 配置定时器4的时基,分频系数为16,自动重载值为0x68  这里68 对应 104  也就是 104us
    TIM4->CNTR = 0; // 将定时器4的计数器清零
}

注释都写在里面了,就不解释了。

最后就是发送函数了

void SimUART_TxByte( u8 SendData )
{
    static u16 Send_All = 0; // 静态变量,用于存储需要发送的10个位的数据
    static u8  BitNum   = 0; // 静态变量,用于记录当前发送的位数
    Send_All = SendData; // 将需要发送的数据存储到 Send_All 变量中
    Send_All = ( Send_All << 1 ) | 0X0200; // 将需要发送的数据转换为10位数据,并存储到 Send_All 变量中
    TIM4->CNTR = 0; // 将定时器4的计数器清零
    TIM4->SR1 &= ~TIM2_SR1_UIF; // 清除定时器4的更新标志位
    // 先发送低位,再发送高位
    for( BitNum = 0;  BitNum<10 ;  BitNum++ )
    {
        if( Send_All & 0X0001 ) // 如果当前位是高电平,发送高电平
        {
            GPIO_WriteHigh(GPIOA, GPIO_PIN_5);
        }
        else // 如果当前位是低电平,发送低电平
        {
            GPIO_WriteLow(GPIOA, GPIO_PIN_5);
        }
        Send_All >>= 1; // 将 Send_All 右移一位,准备发送下一位数据
        // 等待波特率时间
        while( (TIM4->SR1 & TIM4_SR1_UIF) == 0 );
        TIM4->SR1 &= ~TIM4_SR1_UIF; // 清除定时器4的更新标志位
    }
}

当然,关于那个GPIO 的问题,依旧可以使用宏定义,我是只用这一个端口,懒得改了。这样也好理解。

测试结果

上图,使用单片机IO口连接电脑串口,串口助手显示一点问题没有

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值