历史上的今天
返回首页

历史上的今天

今天是:2025年01月22日(星期三)

正在发生

2020年01月22日 | STM8S003软件串口的实现

2020-01-22 来源:eefocus

一切发送和接收的过程都是在后台完成的,具体实现需要一个带捕获&匹配功能的定时器,本实现用的是TIM1。任意具有捕获输入功能的引脚都可以用作接收引脚,任意GPIO引脚都可以用作发送引脚。此实现用TIM_CH4作为发送引脚,TIM1_CH3作为接收引脚。


整个数据传输过程基于定时器1的溢出事件,溢出周期为发送半个bit的时间,这是因为发送和接收用的是同一个定时器。


发送环节:


当有数据字节进入发送缓存后,发送请求标志被置位,最近的一个事件更新中断用于启动此次发送传输,从产生发送请求到开始发送的最长延时为一个溢出周期。在每个偶数的溢出中断中设置相应的发送引脚的电平。


接收环节:


空闲状态下,CH3一直处于输入捕获状态,当捕获到第一个下降沿时(起始位),此时计数器的值会自动保存到CCR3中用于之后的匹配,在捕获中断中将通道模式改为匹配,同时禁止该引脚的捕获/匹配功能,使其成为普通的GPIO引脚,以便检测输入电平。由于半个bit周期的溢出事件存在,所以最近的一次匹配肯定出现在起始位的中间点,此时读取引脚上的电平,以得到该位的逻辑,之后丢弃偶数次的匹配中断,在奇数次匹配中断中读取剩余的位的值,知道接收到完整的一字节数据(包括停止位),将通道模式改为捕获,等待下一字节。  


具体实现代码如


#define BAUDRATE_SWUART         (1200)

#define USR_OVF_ONLY            (0x04)

#define TIM1_CR_CEN             (0x01)      //定时器4计数使能

#define TIM1_SR_UIF             (0x01)

#define TIM1_SR_CC3IF           (0x08)

#define UPDATE_INTER_ENABLE     (0x01)

#define CAP_COMP_INTER_ENABLE3  (0x08)

#define CHANN3_INPUT_TI3FP3     (0x01)

#define CHANN3_OUTPUT           (0xFC)

#define CHANN3_FUNC_MASK        (0x03)

#define CHANN3_CAP_COMP_ENABLE  (0x01)

#define CHANN3_CAP_COMP_DISB    (0xFE)

#define CAP_FALL_EDGE           (0x02)

#define START_BIT_POS           (0x01)      //起始位位置

#ifdef  HAVE_PARITY

#define WORD_LENGTH             (11)        //1个起始位,8个数据位,1个奇偶校验位,1个停止位

#define SET_RCV_BIT             (0x400)

#define STOP_BIT_POS            (0x200)     //停止位位置

#define CHECK_BIT_POS           (0x100)

#else

#define WORD_LENGTH             (10)

#define SET_RCV_BIT             (0x200)

#define STOP_BIT_POS            (0x100)

#endif

#define BIT_MASK                (0x01)

#define EVEN_CHECK              (0)

/*

*********************************************************************************************************

*                                            GLOBAL VARIABLES

*********************************************************************************************************

*/

bool      IsFirstBit;

bool      TxByteReady;

bool      IsOdd;

uint8_t   TxBitCnt;                      //发送位数计数

uint8_t   RxBitCnt;

uint16_t  TxByte;                        //移位发送缓存

uint16_t  RxByte;

/*

*********************************************************************************************************

* Description: Swuart初始化

*

* Arguments  : none

*

* Returns    : none

*

* Notes      : 1200

*********************************************************************************************************

*/

void InitSwuart (void)

{

    TIM1->ARRH = (F_MASTER / (BAUDRATE_SWUART * 2)) >> 8;

    TIM1->ARRL = (uint8_t)(F_MASTER / (BAUDRATE_SWUART * 2));

    TIM1->CR1 = USR_OVF_ONLY;                                   //仅计数器溢出才产生更新事件

    TIM1->CCMR3 = CHANN3_INPUT_TI3FP3;

    TIM1->CCER2 = CHANN3_CAP_COMP_ENABLE | CAP_FALL_EDGE;

    TIM1->IER = UPDATE_INTER_ENABLE |CAP_COMP_INTER_ENABLE3;

    TIM1->CR1 = TIM1_CR_CEN;

    SwuartTxByte(0xFF);                                        //初始化后第一个发送的第一个字节要丢弃

}

/*

*********************************************************************************************************

* Description: 发送一个字节

*

* Arguments  : byte: 待发送的字节

*

* Returns    : none

*

* Notes      : none

*********************************************************************************************************

*/

void SwuartTxByte (uint8_t byte)

{  

    TxByte = byte;

    TxBitCnt = WORD_LENGTH;

                       

    TxByte |= STOP_BIT_POS; //添加停止位

                       

    #ifdef HAVE_PARITY

    if (GetParity(byte, EVEN_CHECK)){

        TxByte |= CHECK_BIT_POS;

    }

    #endif

                       

    TxByte = TxByte << START_BIT_POS;      //添加起始位

                       

    TxByteReady = true;

    IsFirstBit = true;

}

/*

*********************************************************************************************************

* Description: 发送数据

*

* Arguments  : data: 指向待发送数据的指针

*              len:  数据长度

*

* Returns    : none

*

* Notes      : none

*********************************************************************************************************

*/

void SwuartSend (const uint8_t *data , uint8_t len)

{

           uint8_t i;

    static uint8_t SwuartSendBuf[50];

                       

    for (i = 0; i < len; i++){

        SwuartSendBuf[i] = data[i];

    }

                       

    i = 0;

    while (len--){

        SwuartTxByte(SwuartSendBuf[i++]);

        while (TxByteReady){

            ;

        }

    }

}

/*

*********************************************************************************************************

* Description: 奇偶校验

*

* Arguments  : byte: 待校验的字节

*              parity: 校验类型选择

*

* Returns    : none

*

* Notes      : 校验位的值

*********************************************************************************************************

*/

#ifdef HAVE_PARITY

uint8_t GetParity (uint8_t byte, uint8_t parity)

{

    uint8_t  i;

    uint8_t  n;

    uint16_t data;

                       

    data = byte;

    n = 0;

                       

    if (data){

        do{

            i = data & 0x01;

            if ( i > 0 ){

                n++;

            }

            data = data >> 1;

        } while ( data > 0 ) ;

    }

    n = n & 0x01;

                       

    if (parity){      //奇校验

        if(n){

            return 0;

        } else {

            return 1;

        }

    } else {         //偶校验

        if(n){

            return 1;

        } else {

            return 0;

        }

    }

}

#endif

#pragma vector = TIM1_OVF_IRQn

__interrupt void Uart_Tx_Timing (void)

{

    static uint8_t OvfInterCnt;

                       

    TIM1->SR1 &= ~TIM1_SR_UIF;

                       

    if (!TxByteReady){

        return;

    }

    if (IsFirstBit){

        OvfInterCnt = 0;

        IsFirstBit = false;

    }

    if (!(OvfInterCnt % 2) && TxBitCnt){          //丢弃奇数此溢出中断,因为发送1位的时间为两个溢出周期

        GPIOC->ODR.ODR4 = TxByte & BIT_MASK;

        TxByte = TxByte >> 1;

        TxBitCnt--;

    }

    OvfInterCnt++;

    if (!TxBitCnt && !(OvfInterCnt % 2)){         //一个字节发送完毕,保证一个完整的停止位

        TxByteReady = false;

    }

}

#pragma vector = TIM1_CAP_COMP_IRQn

__interrupt void Uart_Rx_Timing (void)

{

           uint8_t tmp;

    static uint8_t CapCompCnt;

                       

    TIM1->SR1 &= ~TIM1_SR_CC3IF;

                       

    if ((TIM1->CCMR3 && CHANN3_FUNC_MASK) == CHANN3_INPUT_TI3FP3){

        TIM1->CCER2 &= CHANN3_CAP_COMP_DISB;                //此处顺序不能颠倒,要先禁止,后修改通道模式

        TIM1->CCMR3 &= CHANN3_OUTPUT;

        CapCompCnt = 1;

        RxBitCnt = WORD_LENGTH;

        RxByte = 0;

        return;

推荐阅读

史海拾趣

Greatbatch-Sierra Inc公司的发展小趣事

机顶盒,全称为数字视频变换盒,是连接电视机与外部信号源的重要设备,其专业性与科普性并重。从广义上讲,机顶盒泛指一切与电视机连接的网络终端设备,能够接收并转换多种信号源,包括有线电缆、卫星天线、宽带网络及地面广播等,为观众提供丰富多样的视听体验。

在数字电视时代,机顶盒扮演了至关重要的角色。它不仅能够接收并解码高清乃至4K超高清的数字电视信号,将其转换为电视机可识别的视频和音频流,还具备网络交互功能,使用户能够享受在线购物、观看网络视频、玩游戏等多元化服务。此外,机顶盒还提供了电子节目指南、因特网网页浏览等增值服务,极大地丰富了用户的娱乐生活。

从技术分类上看,机顶盒可分为多种类型,如DVB-S(数字卫星机顶盒)、DVB-T(数字地面机顶盒)、DVB-C(有线电视数字机顶盒)以及IPTV机顶盒等。每种类型在信号接收和解码方面各有特点,但共同之处在于它们都是连接电视机与外部世界的桥梁,为用户带来更加便捷、丰富的视听享受。

随着智能电视的快速发展,机顶盒的形态也在不断变化。一些智能电视已经内置了机顶盒的功能,实现了电视机与机顶盒的一体化。然而,机顶盒作为独立的设备,在灵活性、扩展性等方面仍具有独特的优势,将继续在数字电视领域发挥重要作用。

Compostar Technology Co Ltd公司的发展小趣事

人才是企业发展的核心。Compostar Technology Co Ltd深知这一点,因此一直注重人才培养和团队建设。公司建立了完善的人才培训体系,为员工提供了广阔的职业发展空间。同时,公司还积极营造良好的企业文化氛围,激发员工的创新精神和团队合作精神。这些举措使得公司拥有一支高素质、高效率的员工队伍,为公司的持续发展提供了有力保障。

Conflux公司的发展小趣事

在竞争激烈的电子行业中,Conflux始终保持对技术创新的追求。公司团队不断研发新的区块链应用场景,如供应链管理、物联网安全等。通过将这些技术应用于实际业务中,Conflux不仅提升了自身的竞争力,也推动了整个电子行业的进步。同时,公司还积极参与国际技术交流和合作,不断引进国际先进理念和技术,为公司的持续创新提供了有力支持。

Gore公司的发展小趣事
在UPS系统中,三电平直流变换器能够提供高质量的直流电源,确保在电网故障时能够稳定供电。
FerriShield公司的发展小趣事

在快速发展的同时,FerriShield始终不忘履行社会责任。公司积极参与环保事业,推动绿色生产和可持续发展。此外,FerriShield还设立了奖学金和助学金,支持贫困地区的青少年接受教育。这些举措体现了FerriShield作为行业领导者的责任与担当。

以上五个故事均基于FerriShield公司的发展历程和事实描述,展现了其在电子行业中的成长和进步。

CCS[Custom Computer Services]公司的发展小趣事

在电子行业中,产品质量和客户服务是企业生存和发展的关键。CCS公司始终坚持质量第一的原则,建立了严格的质量管理体系和客户服务体系。公司从原材料采购到产品生产、销售等各个环节都进行严格的质量控制,确保产品的质量和性能达到客户的期望。同时,CCS公司还提供了全方位的客户服务,包括售前咨询、售后服务和技术支持等,为客户提供了全方位的支持和帮助。

问答坊 | AI 解惑

0-200V压电陶瓷驱动电源

www.zxoe.net 此产品是专为电致伸缩(压电)陶瓷微位移器的闭环控制而设计的驱动电源。     1.技术指标   参数 值 电源电压 220VAC±5% 输出电压 0~200VDC(最多 ...…

查看全部问答>

国产PLC的发展现状--中国自动化网市场研究部

第一节  国产PLC发展历程     作为离散控制的首选产品,PLC在我国的应用已有30年的历史,PLC自20世纪70年代后期进入中国以来,应用增长十分迅速。PLC进入中国时最初是从成套设备引进应用,由于PLC价格昂贵,引进的PLC主要用 ...…

查看全部问答>

BMP图片格式解析

本帖最后由 paulhyde 于 2014-9-15 09:20 编辑 …

查看全部问答>

试试自己的实力吧?是牛人,当然要一马当先!不要犹豫,秀出你自己!

下面的问题请问怎么解决啊?试试自己的实力;我将在五个回帖后给出我的答案。学者共勉啊! 请看下面的超链接: [http://hiphotos.baidu.com/shitoutianxia/abpic/item/4bbc4730d3ffba04eac4af2d.jpg[/url][/url]…

查看全部问答>

RMB 急求GIF降低颜色数和相同区域透明化压缩 DLL或COM组件

RMB 急求GIF降低颜色数和相同区域透明化压缩 (DLL或COM组件) 要求:GIF有5桢左右,每桢一张图,要求能实现相同区域透明化;       能把256色的GIF 压缩为24色或8色的GIF;       开发成组件。 联系Q ...…

查看全部问答>

stm32usb转串口谁能帮忙

                                  …

查看全部问答>

新人

我一个学生,电子信息工程专业的,刚开始学FPGA,还请大家多多指教!…

查看全部问答>

关于AT89C51制作的无线抢答器

请教各位大神我用AT89C51制作一个无线抢答器,用Protuse仿真,他的无线发射电路和无线接收电路应该用那个芯片,怎么样跟单片机连接…

查看全部问答>

新手求问,我这个程序为什么就是进不了中断呢?

我编了一个小程序,意图通过电脑上的串口控制软件,输出1到8这八个数字来控制版上的8个led灯,灯是共阳极的。   思路很简单   就是计时器用19200波特率,SMOD为1,。   采用中断的方式,来了数字后,进入中断。   然后 ...…

查看全部问答>