【电机控制器】FM33LF015芯片——IO口模拟串口

【电机控制器】FM33LF015芯片——IO口模拟串口 @TOC 前言 提示:以下是本篇文章正文内容,下面案例可供参考 一、模拟串口方法 1. 延时法 原理: 延时法是通过精确的延时函数来实现位与位之间的间隔,从而模拟串口通信的时序。这种方法通常适用于较低波特率的情况。 实现步骤: 确定波特率,并计算每位数据的传输时间。 在发送或接收数据时,通过延时函数控制位与位之间的时间间隔。 发送起始位、数据位、校验位(如果有)和停止位。 优缺点: 优点: 实现简单,不需要额外的硬件资源。 缺点: 延时函数的精度受微控制器时钟频率和指令周期的影响,可能不适用于高波特率。此外,延时法会占用CPU资源,影响系统的实时性能。 2. 定时器中断法 原理: 定时器中断法是利用微控制器的定时器对脉冲进行计数,以达到所需的波特率。定时器在达到预定计数值时触发中断,从而在中断服务程序中处理数据的发送或接收。 实现步骤: 配置定时器,设置计数初值和溢出时间。 在定时器中断服务程序中处理数据的发送或接收。 根据波特率调整定时器的计数初值,以确保数据的正确传输。 优点: 能够更精确地控制数据传输的时序,适用于较高波特率。 缺点: 需要配置定时器,并编写中断服务程序,增加了编程的复杂性。此外,如果模拟多个串口,可能需要多个定时器资源。 3. 外部中断+定时器中断法 原理: 外部中断+定时器中断法结合了外部中断的触发灵活性和定时器中断的精确时序控制。外部中断用于检测数据的起始位或停止位,定时器中断用于在数据传输过程中采样数据位。 实现步骤: 配置外部中断引脚,设置为下降沿或上升沿触发。 在外部中断服务程序中启动定时器,并设置定时器的计数初值。 在定时器中断服务程序中采样数据位,并根据采样结果构建接收到的数据。 当接收到停止位时,结束数据接收过程。 优点: 结合了外部中断和定时器中断的优点,能够更灵活地处理数据的发送和接收,适用于多种波特率和通信协议。 缺点: 需要同时配置外部中断和定时器,编程复杂度较高。此外,对定时器的精度和中断响应速度有一定要求。 4. 捕获法 原理: 捕获法通常利用微控制器的捕获单元(如定时器/计数器的捕获功能)来检测数据的起始位和停止位,并在数据传输过程中捕获数据位。这种方法需要微控制器具有捕获单元硬件支持。 实现步骤(假设微控制器具有捕获单元): 配置捕获单元,设置捕获触发条件和捕获寄存器。 当捕获到起始位时,启动捕获过程。 在捕获过程中,根据波特率定时采样数据位,并将采样结果存储在捕获寄存器中。 当捕获到停止位时,结束捕获过程,并处理接收到的数据。 优缺点(基于捕获单元的存在和配置): 优点: 能够精确地捕获数据的起始位、数据位和停止位,适用于高波特率和复杂通信协议。 缺点: 需要微控制器具有捕获单元硬件支持,且捕获单元的配置和使用可能相对复杂。此外,捕获法的实现可能受到微控制器型号和捕获单元性能的限制。 二. 代码 1.Suart.c /* * File: Suart.c * Author: GDX * Date: 2025-1-21 * Description: This is a simulate uart file * Version: 1.0 */ #include "config.h" #include "fm33lg0xx_fl.h" SuartTypedef Suart; SuartStateTypedef SuartState; /* * Function: Timer_1ms_Deal * Description: Timer_1ms_Deal * Input: unsigned char data * Output: none * Returns: none */ void f_Suart_Send(unsigned char data) { unsigned char i; /* start bit */ DISPLAY_TXD_L(); FL_DelayUs(SUART_DELAY); /* data bit */ for(i=0; i>= 1; FL_DelayUs(SUART_DELAY); } /* stop bit */ DISPLAY_TXD_H(); FL_DelayUs(SUART_DELAY); } /* * Function: f_Suart_Tx_Byte * Description: f_Suart_Tx_Byte * Input: unsigned char *ptr,unsigned char len * Output: none * Returns: none */ void f_Suart_Tx_Byte(unsigned char *ptr,unsigned char len) { unsigned short i; for(i=0;iSUART_IDLE_TIMES) { Suart_Rxd_Idle=0; FL_GPTIM_WriteCounter(GPTIM1,0); FL_GPTIM_WriteAutoReload(GPTIM1,Suart.samp_t-1); /* close timer */ FL_GPTIM_Disable(GPTIM1); //FL_GPIO_ClearFlag_EXTI(GPIO,FL_GPIO_EXTI_LINE_1); /* open iqr */ NVIC_EnableIRQ(GPIO_IRQn); //Suart.flag=1; } } break; case SuartState_DATA: /* data bit */ if(Suart_Rxd_Bit==1) { Suart_Rxd_Byte|=Suart_Rxd_Num; } Suart_Rxd_Num=Suart_Rxd_NumDIN & DISPLAY_RXD_PIN)=0) extern void f_Suart_Send(unsigned char data); extern void f_Suart_Tx_Byte(unsigned char *ptr,unsigned char len); extern void f_Suart_Tx_String(unsigned char *ptr); extern void f_Suart_Init(void); extern void f_GPTIM1_SUART_IRQHandler(void); #endif 三、实验 四、参考资料 单片机中的 nop() 延时以及其相关的基础扩展 嵌入式开发十六:外部中断实验1:通过外部中断控制灯亮灭 用IO口模拟串口(外部中断+定时器)--附程序附测试结果 一文读懂大端、小端、字节序、MSB、LSB、MSBs、LSBs 使用单片机普通IO口模拟串口的三种方法 IO口模拟串口的几种"硬核"操作 总结 本文仅仅简单介绍了【电机控制器】FM33LF015芯片——IO口模拟串口,评论区欢迎讨论。

Mar 28, 2025 - 08:10
 0
【电机控制器】FM33LF015芯片——IO口模拟串口

【电机控制器】FM33LF015芯片——IO口模拟串口

@TOC

前言

提示:以下是本篇文章正文内容,下面案例可供参考

一、模拟串口方法

1. 延时法

原理:
延时法是通过精确的延时函数来实现位与位之间的间隔,从而模拟串口通信的时序。这种方法通常适用于较低波特率的情况。

实现步骤:
确定波特率,并计算每位数据的传输时间。
在发送或接收数据时,通过延时函数控制位与位之间的时间间隔。
发送起始位、数据位、校验位(如果有)和停止位。
优缺点:

优点:
实现简单,不需要额外的硬件资源。

缺点:
延时函数的精度受微控制器时钟频率和指令周期的影响,可能不适用于高波特率。此外,延时法会占用CPU资源,影响系统的实时性能。

2. 定时器中断法

原理:
定时器中断法是利用微控制器的定时器对脉冲进行计数,以达到所需的波特率。定时器在达到预定计数值时触发中断,从而在中断服务程序中处理数据的发送或接收。

实现步骤:
配置定时器,设置计数初值和溢出时间。
在定时器中断服务程序中处理数据的发送或接收。
根据波特率调整定时器的计数初值,以确保数据的正确传输。

优点:
能够更精确地控制数据传输的时序,适用于较高波特率。

缺点:
需要配置定时器,并编写中断服务程序,增加了编程的复杂性。此外,如果模拟多个串口,可能需要多个定时器资源。

3. 外部中断+定时器中断法

原理:
外部中断+定时器中断法结合了外部中断的触发灵活性和定时器中断的精确时序控制。外部中断用于检测数据的起始位或停止位,定时器中断用于在数据传输过程中采样数据位。

实现步骤:
配置外部中断引脚,设置为下降沿或上升沿触发。
在外部中断服务程序中启动定时器,并设置定时器的计数初值。
在定时器中断服务程序中采样数据位,并根据采样结果构建接收到的数据。
当接收到停止位时,结束数据接收过程。

优点:
结合了外部中断和定时器中断的优点,能够更灵活地处理数据的发送和接收,适用于多种波特率和通信协议。

缺点:
需要同时配置外部中断和定时器,编程复杂度较高。此外,对定时器的精度和中断响应速度有一定要求。

4. 捕获法

原理:
捕获法通常利用微控制器的捕获单元(如定时器/计数器的捕获功能)来检测数据的起始位和停止位,并在数据传输过程中捕获数据位。这种方法需要微控制器具有捕获单元硬件支持。

实现步骤(假设微控制器具有捕获单元):
配置捕获单元,设置捕获触发条件和捕获寄存器。
当捕获到起始位时,启动捕获过程。
在捕获过程中,根据波特率定时采样数据位,并将采样结果存储在捕获寄存器中。
当捕获到停止位时,结束捕获过程,并处理接收到的数据。
优缺点(基于捕获单元的存在和配置):

优点:
能够精确地捕获数据的起始位、数据位和停止位,适用于高波特率和复杂通信协议。
缺点:

需要微控制器具有捕获单元硬件支持,且捕获单元的配置和使用可能相对复杂。此外,捕获法的实现可能受到微控制器型号和捕获单元性能的限制。

二. 代码

1.Suart.c

/*
* File: Suart.c
* Author: GDX
* Date: 2025-1-21
* Description: This is a simulate uart file
* Version: 1.0
*/
#include "config.h"
#include "fm33lg0xx_fl.h"
SuartTypedef Suart;
SuartStateTypedef SuartState;
/*
* Function: Timer_1ms_Deal
* Description: Timer_1ms_Deal
* Input: unsigned char data
* Output: none
* Returns: none
*/
void f_Suart_Send(unsigned char data)
{
    unsigned char i;
  /* start bit */
  DISPLAY_TXD_L();
  FL_DelayUs(SUART_DELAY);
    /* data bit */
  for(i=0; i<8; i++)
  {
    if(data & 0x01)
    {
      DISPLAY_TXD_H();
    }
    else
    {
      DISPLAY_TXD_L();
    }
    data >>= 1;
    FL_DelayUs(SUART_DELAY);
  }
  /* stop bit */
  DISPLAY_TXD_H();
  FL_DelayUs(SUART_DELAY);
}
/*
* Function: f_Suart_Tx_Byte
* Description: f_Suart_Tx_Byte
* Input: unsigned char *ptr,unsigned char len
* Output: none
* Returns: none
*/
void f_Suart_Tx_Byte(unsigned char *ptr,unsigned char len)
{
    unsigned short i;
  for(i=0;i<len;i++)
  {
       f_Suart_Send(ptr[i]);
  }
}
/*
* Function: f_Suart_Tx_String
* Description: f_Suart_Tx_String
* Input: unsigned char *ptr
* Output: none
* Returns: none
*/
void f_Suart_Tx_String(unsigned char *ptr)
{
    while( *ptr != 0 )
    {
        f_Suart_Send( *ptr );
        ptr++;
    }
}
/*
* Function: f_Suart_Init
* Description: f_Suart_Init
* Input: none
* Output: none
* Returns: none
*/
void f_Suart_Init(void)
{   
    Suart.baud_t=SUART_TIMER_FREQUENCE/SUART_BAUD;
    Suart.samp_t=Suart.baud_t*SUART_START_BIT_FACTOR;
}
/*
* Function: f_GPTIM1_SUART_IRQHandler
* Description: f_GPTIM1_SUART_IRQHandler
* Input: none
* Output: none
* Returns: none
*/
void f_GPTIM1_SUART_IRQHandler(void)
{
    unsigned char Suart_Rxd_Bit=1;
    static unsigned char Suart_Rxd_Byte;
    static unsigned char Suart_Rxd_Num;
    static unsigned char Suart_Rxd_Idle;
    static unsigned char Suart_Rxd_Sync_Count;
    Suart_Rxd_Bit=FL_GPIO_GetInputPin(DISPLAY_RXD_GPIO,DISPLAY_RXD_PIN);//DISPLAY_RXD_P();//
    switch(SuartState)
  {
    case SuartState_START:
            /* start_bit */
            NVIC_DisableIRQ(GPIO_IRQn);
            if(Suart_Rxd_Bit==0)
            {   
                Suart_Rxd_Num = 0x01;
                Suart_Rxd_Byte = 0;
                Suart_Rxd_Idle = 0;
                FL_GPTIM_WriteCounter(GPTIM1,0);
                FL_GPTIM_WriteAutoReload(GPTIM1,Suart.baud_t-1);
                SuartState=SuartState_DATA;
            }
            /* idle  */
            else if(Suart_Rxd_Bit==1)
            {   
                Suart_Rxd_Idle++;
                if(Suart_Rxd_Idle>SUART_IDLE_TIMES)
                {   
                    Suart_Rxd_Idle=0;
                    FL_GPTIM_WriteCounter(GPTIM1,0);
                    FL_GPTIM_WriteAutoReload(GPTIM1,Suart.samp_t-1);
                    /* close timer */
                    FL_GPTIM_Disable(GPTIM1);
                    //FL_GPIO_ClearFlag_EXTI(GPIO,FL_GPIO_EXTI_LINE_1);
                    /* open iqr */
                    NVIC_EnableIRQ(GPIO_IRQn);
                    //Suart.flag=1;
                }   
            }   
            break;
        case SuartState_DATA:   
            /* data bit */
            if(Suart_Rxd_Bit==1)
            {       
                Suart_Rxd_Byte|=Suart_Rxd_Num;
            }   
            Suart_Rxd_Num=Suart_Rxd_Num<<1;
            /* 8 data receive finish */
            if(Suart_Rxd_Num==0) 
            {   
                f_Suart_Send(Suart_Rxd_Byte);
                SuartState=SuartState_STOP;
            }   
            break;
        case SuartState_STOP:
            /* stop bit */
            if(Suart_Rxd_Bit==1)
            {   
        Suart.buff[Suart.len++]=Suart_Rxd_Byte;
                //f_Suart_Tx_Byte(Suart.buff,Suart.len);
                Suart_Rxd_Sync_Count++;
                if(Suart_Rxd_Sync_Count==SUART_SYNC_TIMES)
                {   
                    Suart_Rxd_Sync_Count=0;
                    Suart_Rxd_Byte=0;
                    FL_GPTIM_WriteCounter(GPTIM1,0);
                    FL_GPTIM_WriteAutoReload(GPTIM1,Suart.samp_t-1);
                    //FL_GPIO_ClearFlag_EXTI(GPIO,FL_GPIO_EXTI_LINE_1);
                    NVIC_EnableIRQ(GPIO_IRQn);
                }
                SuartState=SuartState_START;
            }
            break;
        default:
            /* deal unknow state */
            break;
  }
}

2.Suart.h

#ifndef __SUART_H__
#define __SUART_H__

#if defined(FM33LG0XX)
#include "fm33lg0xx_fl.h"
#elif defined(FM33LC0XX)
#include "fm33lc0xx_fl.h"
#endif

#include "main.h"

#define SUART_TIMER_FREQUENCE   1000000 
#define SUART_BAUD                          9600
#define SUART_START_BIT_FACTOR  0.5
/* TXD Delay Time : Test acually value */
#define SUART_DELAY                         43              
#define SUART_IDLE_TIMES                3               
#define SUART_SYNC_TIMES                5
#define SUART_BUFF_LEN                  200

/* SuartState bit config */
typedef struct
{   
    unsigned int baud_t;
  unsigned int samp_t;                              /* samp timer */
  unsigned char process;                        /* receive deal process */
  unsigned char buff[SUART_BUFF_LEN];   /* receive buff */
  unsigned char len;                                /* receive buff len */
  unsigned char flag;      
}SuartTypedef;
extern SuartTypedef Suart;

/* SuartState frame config */
typedef enum
{   
    SuartState_START,
    SuartState_DATA,
    SuartState_STOP,
    SuartState_MAX,
}SuartStateTypedef;
extern SuartStateTypedef SuartState;

/* TXD config */
#define DISPLAY_TXD_GPIO        GPIOA
#define DISPLAY_TXD_PIN             FL_GPIO_PIN_4
#define DISPLAY_TXD_H()           FL_GPIO_SetOutputPin(DISPLAY_TXD_GPIO,DISPLAY_TXD_PIN)
#define DISPLAY_TXD_L()           FL_GPIO_ResetOutputPin(DISPLAY_TXD_GPIO,DISPLAY_TXD_PIN)

/* RXD config */
#define DISPLAY_RXD_GPIO        GPIOA
#define DISPLAY_RXD_PIN             FL_GPIO_PIN_5
#define DISPLAY_RXD_P()           ((DISPLAY_RXD_GPIO ->DIN & DISPLAY_RXD_PIN)!=0)
#define DISPLAY_RXD_N()           ((DISPLAY_RXD_GPIO ->DIN & DISPLAY_RXD_PIN)=0)

extern void f_Suart_Send(unsigned char data);
extern void f_Suart_Tx_Byte(unsigned char *ptr,unsigned char len);
extern void f_Suart_Tx_String(unsigned char *ptr);
extern void f_Suart_Init(void);
extern void f_GPTIM1_SUART_IRQHandler(void);
#endif

三、实验

在这里插入图片描述

四、参考资料

单片机中的 nop() 延时以及其相关的基础扩展
嵌入式开发十六:外部中断实验1:通过外部中断控制灯亮灭
用IO口模拟串口(外部中断+定时器)--附程序附测试结果
一文读懂大端、小端、字节序、MSB、LSB、MSBs、LSBs
使用单片机普通IO口模拟串口的三种方法

IO口模拟串口的几种"硬核"操作

总结

本文仅仅简单介绍了【电机控制器】FM33LF015芯片——IO口模拟串口,评论区欢迎讨论。