历史上的今天
返回首页

历史上的今天

今天是:2025年04月02日(星期三)

正在发生

2019年04月02日 | 模拟串口UART的实现

2019-04-02 来源:eefocus

最近在调的MCU的型号为STM32F030,配置芯片相较之前的MCU都比较简单,功能配置很顺利。但是在写串口程序的时候,发现串口一直不通,使用示波器也没有波形。因为基本的串口通讯线只有Tx和Rx两根线,配置也相对简单,8位数位,1位停止位,9600波特率。协议结构为 起始位(低电平)+8位数据(低位在前)+1位停止位(高电平),例如发送字节0x55,即电平为低 高低高低高低高低 高。电平转换的间隔时间为1s/9600 = 104us


以上均为理论分析过程,检查代码对串口的配置都没有发现错误。最终排查的结果是硬件工程师画原理图和PCB图时将串口的Tx和Rx画反了!由于某些原因板子已经量产了,故只能通过改软件来实现串口的功能,在网上找了一下发现模拟串口可行性可以,故动手写了一下模拟串口。


串口通讯需要模拟两根线(Tx和Rx)的时序,模拟串口的主要思路如下:


发送部分比较简单,按照 起始位(低电平)+8位数据(低位在前)+1位停止位(高电平),间隔时间104us,即可。


接收部分有点复杂,需要配置一个外部中断,用于检测低电平信号,还需要一个定时器,用于读取有效数据。


下面将代码附上:


发送IO口初始化


/*!

 * @brief 模拟串口1 TX IO口配置

 * @param none

 * @return none

 * @note Tx(PA10)

 */

void MUSART1_TX_init(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;  

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;

    GPIO_Init(GPIOA, &GPIO_InitStructure); 

    GPIO_SetBits(GPIOA, GPIO_Pin_10);

}


接收IO口初始化


/*!

 * @brief 模拟串口1 RX IO口配置

 * @param none

 * @return none

 * @note Rx(PA9)

 */

void MUSART1_RX_init(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;

    EXTI_InitTypeDef EXTI_InitStructure;

    NVIC_InitTypeDef NVIC_InitStructure;

      

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);    //!<外部中断时钟


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;

    GPIO_Init(GPIOA, &GPIO_InitStructure); 


    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource9);  

    

    EXTI_InitStructure.EXTI_Line=EXTI_Line9;  

    EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;  

    EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;    //下降沿中断

    EXTI_InitStructure.EXTI_LineCmd=ENABLE;  

    EXTI_Init(&EXTI_InitStructure); 

     

    NVIC_InitStructure.NVIC_IRQChannel=EXTI4_15_IRQn;  

    NVIC_InitStructure.NVIC_IRQChannelPriority=0x01;  

    NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;  

    NVIC_Init(&NVIC_InitStructure);

}

定时器初始化


/*!

 * @brief 定时器14初始化 

 * @param

 * @return NONE

 * @note 103us定时器,用于串口数据采样

 */

void Time14Init(void)

{

    TIM_TimeBaseInitTypeDef TIM_TimerBaseStruct;

 

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE);   //!<时钟使能

    TIM_DeInit(TIM14);     //!

    TIM_TimerBaseStruct.TIM_Period=103;          //!<设置重载寄存器初值 (设置为103,即:定时104us)

    TIM_TimerBaseStruct.TIM_Prescaler=7;      //!<使用内部8M时钟,分频8(7+1),8M/8 = 1000000,故数1000000(999999+1)下,达1秒

    TIM_TimerBaseStruct.TIM_ClockDivision=0;     //!<不分频

    TIM_TimerBaseStruct.TIM_CounterMode=TIM_CounterMode_Up; //!<设置计数器向上计数模式

    TIM_TimeBaseInit(TIM14,&TIM_TimerBaseStruct);

 

    NVIC_InitTypeDef NVIC_InitStructure;

    NVIC_InitStructure.NVIC_IRQChannel=TIM14_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPriority=2;

    NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

    NVIC_Init(&NVIC_InitStructure);

    TIM_ClearITPendingBit(TIM14, TIM_FLAG_Update);

    TIM_ITConfig(TIM14,TIM_IT_Update,ENABLE);      //!<使能TIM1中断源

    TIM_Cmd(TIM14,DISABLE);                          //!<禁能TIM1定时器


}

发送数据函数


uint32 delayTime =99; //!<9600,理论值为104但实际测下来99时效果最好

/*!

 * @brief 模拟串口1发送一个字节

 * @param

 * @return none

 * @note 数据低位在前高位在后

 */

void MUSART1_SendData(uint8 data)

{

uint8 i = 0;

TX_L(); //!<起始位

delay_us(delayTime);

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

if(data & 0x01)

TX_H();

else

TX_L();

delay_us(delayTime);

data >>= 1;

}

TX_H(); //!<停止位

delay_us(delayTime);

}

接收数据,外部中断起始接收


/*!

 * @brief 串口接收IO中断处理函数

 * @param none

 * @return NONE

 * @note none

 */

void EXTI4_15_IRQHandler(void)

{

if (EXTI_GetITStatus(EXTI_Line9) != RESET){

if(RX_READ() == 0x00){

if(rx_state >= STATE_STOP){

recvData = 0;

rx_state = STATE_START;

delay_us(50);

TIM_Cmd(TIM14, ENABLE); //!<打开定时器,接收数据

}

}

        EXTI_ClearITPendingBit(EXTI_Line9);

    }

}

接收数据,定时器中断接收数据


/*!

 * @brief 定时器1中断处理函数

 * @param

 * @return NONE

 * @note  

 */

void TIM14_IRQHandler(void)

{

if(TIM_GetITStatus(TIM14, TIM_IT_Update) != RESET){

  rx_state++;                         //!<改变状态机

if(rx_state == STATE_STOP){

TIM_Cmd(TIM14, DISABLE);    //!<关闭定时器

usart_getByte();            //!<接收到停止位之后,处理数据recvData

return;                     //!<返回

}

if(RX_READ()){

recvData |= (1 << (rx_state - 1));

}else{

recvData &= ~(1 <<(rx_state - 1));

}

TIM_ClearITPendingBit(TIM14, TIM_FLAG_Update);

}

}

其他说明

typedef enum{

STATE_START=0,

STATE_BIT0,

STATE_BIT1,

STATE_BIT2,

STATE_BIT3,

STATE_BIT4,

STATE_BIT5,

STATE_BIT6,

STATE_BIT7,

STATE_STOP

}RX_STATE;

 

RX_STATE rx_state = STATE_STOP;

uint8 recvData=0;    //!<接收的一个字节数据,全局变量

至此,模拟串口的代码及原理均已描述完成。单独的串口通讯并没有问题,但是在实际应用中采取了一种特殊的“总线”形式。

本次写的是从机部分的代码,从机接收数据并没有问题,但是在发送数据时,由于所有的从机Tx都挂载在同一根Tx上,并且从机Tx空闲状态时一直是高电平,导致指定从机的起始信号发不出去。故需要再做以下处理,解决以上问题。


当接收到的数据包中的ID为本从机ID时将Tx拉高,否则拉低,这样能够保证当指定ID的从机发送数据时有且只有一个从机再总线上发送数据(其他从机的Tx主动离线)。


好了就记录这么多。


推荐阅读

史海拾趣

泰科天润(GPT)公司的发展小趣事

机顶盒,全称数字视频变换盒,是连接电视与外部信号源的重要设备,其专业性与科普性均不容忽视。从广义上讲,任何与电视机连接的网络终端设备均可视为机顶盒,它们承担着将各种信号源转换为电视可识别并播放的格式的重要任务。

机顶盒的核心功能在于接收、解码和显示。它能接收来自有线电缆、卫星天线、宽带网络及地面广播等多种传输介质的数字电视信号,并通过内置的解调器和解码器,将这些信号转换为电视能够播放的视频和音频流。这一过程中,机顶盒展现了其强大的技术实力,确保用户能够享受到高质量的视听体验。

随着技术的发展,机顶盒不断进化。从最初的模拟频道增补器、解码器,到如今支持高清、4K乃至8K超高清播放的智能网络机顶盒,机顶盒的每一次升级都带来了更加丰富的内容选择和更加便捷的使用体验。同时,网络机顶盒的出现更是将电视与互联网紧密相连,使得用户能够通过电视屏幕浏览网页、观看在线视频、下载应用程序、享受交互式娱乐等多元化服务。

此外,机顶盒还具备强大的扩展性和可定制性。通过搭载不同的软件和硬件设备,机顶盒可以满足不同用户的个性化需求,如家庭影院功能、社交媒体互动、语音控制等。这些功能的加入不仅提升了机顶盒的实用性,也使其成为了现代家庭娱乐的重要组成部分。

综上所述,机顶盒作为连接电视与外部世界的桥梁,其专业性与科普性在不断提升中。随着技术的不断进步和市场的不断扩大,机顶盒将继续为用户带来更加优质、便捷、智能的视听体验。

ATO SOLUTION公司的发展小趣事

在电子行业的激烈竞争中,ATO SOLUTION公司通过一项创新性的技术突破,成功引领了市场的新潮流。该公司研发出了一款高效能的半导体芯片,极大地提升了电子设备的性能和能效比。这一技术的问世,迅速获得了行业内外的广泛关注和认可,为公司赢得了大量合作伙伴和客户,奠定了市场领先地位。

Exar公司的发展小趣事

为了进一步扩大市场份额,Exar公司开始积极拓展全球市场。公司加大了对海外市场的投入力度,通过参加国际展会、建立海外分支机构等方式,不断提升品牌知名度和市场影响力。同时,Exar还积极与当地企业合作,共同开拓市场,实现了互利共赢。

Carlo Gavazzi公司的发展小趣事

随着技术的不断进步和市场需求的不断变化,Carlo Gavazzi公司始终保持着创新的活力。公司不断推出新产品,从最初的电气元件到后来的控制和自动化解决方案,再到能源管理和节能方案,产品线日益丰富。这种多元化的产品策略不仅满足了客户的多样化需求,也为公司带来了更广阔的市场空间。

Gulf Semiconductor公司的发展小趣事

随着技术的不断进步和市场需求的不断变化,Carlo Gavazzi公司始终保持着创新的活力。公司不断推出新产品,从最初的电气元件到后来的控制和自动化解决方案,再到能源管理和节能方案,产品线日益丰富。这种多元化的产品策略不仅满足了客户的多样化需求,也为公司带来了更广阔的市场空间。

HiRel Connectors Inc公司的发展小趣事
对于安装在户外的摄像头,应安装防雷击保护装置以减少因雷击而导致的损坏。

问答坊 | AI 解惑

高手看看显示程序哪里出错啊

;--------------------------------------- ;  四位共阳LED动态扫描显示程序 ;  P0为段码口,P2为位选口(低电平有效) ;  参数为要显示的字符串指针 ;---------------------------------------    & ...…

查看全部问答>

美资公司LSI上海研发中心诚聘 Test Engineer

美资公司LSI上海研发中心诚聘 Test Engineer 内部推荐,有意者请将中英文简历发送至:asic_tapeout@hotmail.com Test Engineer DESCRIPTION OF DUTIES IN ADDITION TO THOSE IN JOB DESCRIPTION: - To support prototype and production relea ...…

查看全部问答>

使用串口老出现ttys input overruns!

使用串口老出现ttys input overruns!有谁知道!如何解决!或是什么问题引起的!谢谢了先!…

查看全部问答>

请教怎样把很大的数组放到2407的FLASH中?!

我用到液晶显示,但是由于液晶本身的CGRAM=2K远远不够存入我要显示的自定义字符数组(大约有三百个中文字,按照16*16*300来计算,要用到将近10K的空间.所以我想把这些数组放到FLASH中,请教应该如何设置才能实现此功能? 万分感谢!…

查看全部问答>

求证:"TI MSP430大学计划教材"中,5V的液晶显示器可与MSP430的I/O口直接相连,可以吗???

"TI MSP430大学计划教材"-"MSP430系列16位超低功耗单片机原理与应用"一书中,第306页和309页的电路图均表示5V的液晶显示器可与MSP430的I/O口直接相连,可以吗???,这对我很重要,因我要将51系统改为用MSP430.…

查看全部问答>

C51增强型单片机程序集

非常好的程序集,与大家分享,不要错过啊,不学习没道理!呵呵,祝大家好运!…

查看全部问答>

TI送的MSP430软件开发指南的P66页的这周期计算为什么要乘以2呢?我觉得应该不要呀

TI送的MSP430软件开发指南的P66页的这周期计算为什么要乘以2呢?我觉得应该不要呀!书上写的是增计数模式周期应该是CCR0/f呀!求指导 …

查看全部问答>

【晒样片】慷慨TI样片申请之TPS65980

本帖最后由 风雪天殇 于 2014-7-25 15:28 编辑 前几天看到这个活动,这种鼠标一点就有奖励神马的最有爱了,果断点了链接,本着申请不浪费的原则,选了个TPS65980,虽然仍有很大可能用不上....当然那个SN74LVC1G08也有可能用得上,但是太便宜了的 ...…

查看全部问答>

可变周期脉冲发生器的设计

信号为50mhz固定,要用分频来实现不同的型号输入。 设计一个周期、占空比可调的脉冲发生器。脉冲产生过程中,可对脉冲的周期、高电平和低电平的延续时间进行调整;调整步长自定;并同时显示已经输出的脉冲的个数,若脉冲个数达到了数码管显示的极 ...…

查看全部问答>

今年题目预测有可能出现红外吗?

今年题目预测有可能出现红外吗? …

查看全部问答>