中颖51芯片学习6. EUART接口通讯

一、资源介绍

SH79F9476 有3个自带波特率发生器的EUART0/1/2(波特率发生器是一个15位向上计数器)。
SH79F9476的EUART有四种工作方式,3个EUART功能基本一样。下面主要介绍 EUART0。

二、工作方式介绍

1. 四种通讯方式

(1)方式0:同步通信

波特率由系统时钟频率决定,帧长度为8位,无起始位、停止位和第9位。在这种模式下,通信开始时等待RIx标志位(接收中断标志)为0并且RENx标志位(接收使能标志)为1,然后发送一个时钟信号到TXDx引脚,并在RXDx引脚上接收8位数据。

(2)方式1:异步通信

波特率由EUART自带的波特率发生器控制,波特率为溢出率除以16,帧长度为10位(1个起始位、8位数据、1个停止位),没有第9位。在这种模式下,通信开始时从输入的起始位初始化接收,并且都设置为1。

(3)方式2:异步通信

,波特率由系统时钟频率决定,帧长度为11位(1个起始位、8位数据、1个停止位、1个第9位),第9位可设置为0或1。波特率由系统时钟频率除以32或64决定。

(4)方式3:异步通信

波特率由EUART自带的波特率发生器控制,波特率为溢出率除以16,帧长度为11位(1个起始位、8位数据、1个停止位、1个第9位),第9位可设置为0或1。在这种模式下,通信开始时从输入的起始位初始化接收,并且都设置为1。

通过配置SCON寄存器的SM0、SM1用来配置运行方式,如下图所示:

SM0SM1方式类型波特率帧长度起始位停止位第 9 位
000同步fSYS/(4 或 12)8 位
011异步自带波特率发生器的溢出率/1610 位11
102异步fSYS/(32 或 64)11 位110,1
113异步自带波特率发生器的溢出率/1611 位110,1

2. 波特率计算公式

(1)方式0

波特率可编程为系统时钟的1/12或1/4,由SMx2位决定。

  • 当SMx2为0时,串行端口在系统时钟的1/12下运行。
  • 当SMx2为1时,串行端口在系统时钟的1/4下运行。

(2)方式1和方式3中,波特率可微调

精度为一个系统时钟,公式 如下:
B a u d R a t e = F s y s 16 ∗ ( 32768 − S B R T ) + S F I N E BaudRate = \frac{F_{sys}}{16*(32768-SBRT)+SFINE} BaudRate=16(32768SBRT)+SFINEFsys
以系统时钟24M为例,要得到9600Hz波特率:

(int)X=FSY/(16波特率) ;
SBRT=32768-X ;
SFINE=(FSY/波特率)-16
X
FSY=8M

为便于参数计算,在开源仓库的docs文件件放了波特率计算的Excel公式 。
使用时填写波特率、系统频率,自动计算的 合并一栏,即要给 SBRTH、SBRTL赋的值,SFINE在下面对应单元格。

在这里插入图片描述
在这里插入图片描述
波特率9600计算结果示例:
在这里插入图片描述

SBRTH=0xff;
SBRTL=0x64; 
SFINE=0x04;

(3)方式2

波特率固定为系统时钟的1/32或1/64,由SMOD位(PCON.7)决定 。

三、寄存器

1. EUART0控制及状态寄存器

在这里插入图片描述

2. EUART0 数据缓冲寄存器

在这里插入图片描述

3. 波特率发生器寄存器

在这里插入图片描述

4. 波特率发生器微调寄存器

在这里插入图片描述

开启中断

EUART0的中断允许位在IEN0, 位置如图所示:
在这里插入图片描述

通过下面代码 开启EUART0的中断:

IEN0 |= 0x10; 

四、实验代码

1. 硬件连接

  • TX:引脚 P3.3
  • RX:引脚 P3.4
    在这里插入图片描述
    通过USB转串口工具,将串口连接到电脑,并打开串口助手进行调试。

2. 简单的收发代码

下面代码实现的功能是:

  • mcu启动时,向串口发送字符0x32。
  • 串口收到字符时,将数值+1后,通过串口再发出去。

要注意的是,代码选项:“内部 128kHz RC 振荡器作为振荡器 1,24MHz 内部 RC 作为振荡器 2”,如下图所示:
在这里插入图片描述

(1)euart_utils.h

#include "intrins.h"
#include "euart_utils.h"
#include "api_ext.h"
#include "SH79F9476.h"
#include "cpu.h"
/**
* @brief 初始化串口
*/
void uart0_init(){
    //=====TX 建议配置为输出H====
    P3CR = 0x08;
    P3 = 0x08;
    // 配置Uart工作在模式1
    select_bank1();
		// 0110 0111 Tx:P3.3   Rx:P3.4
    UART0CR = 0x67;
    select_bank0();
    SCON=0x50; 
    /*配置波特率参数,波特率9600*/
    /* 计算公式:(int)X=FSY/(16*波特率) ;  SBRT=32768-X  ;   SFINE=(FSY/波特率)-16*X   FSY=8M*/
		// 波特率发生器高位
    SBRTH = 0xFF;
		// 波特率发生器低位
    SBRTL = 0x64;
		// 波特率发生器微调
    SFINE = 0x04;
}
/**
* @brief 发送一个字节
*/
void uart0_send_byte(u8 byte){
    SBUF = byte;
    while(!TI);
    TI = 0;
}
/**
* @brief UART0中断
**/
void INT_EUART0(void) interrupt 4{
	u8 dat;
	_push_(INSCON);
	
	// 收的数值+1 再返回去
	while(!RI);
	dat = SBUF;
	RI = 0;   
	_pop_(INSCON); 

	dat ++;
	uart0_send_byte(dat);      
}

(2)main.c

#include "SH79F9476.h"
#include "cpu.h"
#include "intrins.h"
#include "api_ext.h"
#include "clk_util.h"
#include "euart_utils.h"
#include "irq_util.h"


void main()
{
	// 选择高速时钟
	highFrequenceClk();
	
	// 串口初始化
	uart0_init();
	// 开启中断
	enableAllIrq();
	enableEUart0();
	uart0_send_byte(0x32);
	while (1);
}

在这里插入图片描述

3. 通过发送缓冲区发送数据

上面的发送串口数据的方法,由于在发送的时候要等待 TI 标志位完成,在发送时会造成程序阻塞,影响其它程序的运行。
为了避免这种影响,可以将发送改在中断中来完成,实现方法是:

  1. 将要发送的数据放到发送缓冲区
  2. 把发送缓冲区当前指针位置赋值给SBUF,并将指针移到下一个元素
  3. 发送完成时,触发中断
  4. 如果未发送完,回到第2步发送

代码示例

#include "intrins.h"
#include "euart_utils.h"
#include "api_ext.h"
#include "SH79F9476.h"
#include "cpu.h"
#include "string.h"

// 发送缓冲区
U8 gUart0DataTxD[UART0_DATA_BUF_SIZE];
// 未发送数据长度
U8 gUart0Len_TxD = 0;

// 内部变量,发送指针
volatile U8 *ptr_tx0;

/**
* @brief 初始化串口
*/
void Uart0_Init() {
    //=====TX 建议配置为输出H====
    P3CR = 0x08;
    P3 = 0x08;
    // 配置Uart工作在模式1
    select_bank1();
    // 0110 0111 Tx:P3.3   Rx:P3.4
    UART0CR = 0x67;
    select_bank0();
    SCON = 0x50;
    /*配置波特率参数,波特率9600*/
    /* 计算公式:(int)X=FSY/(16*波特率) ;  SBRT=32768-X  ;   SFINE=(FSY/波特率)-16*X   FSY=8M*/
    // 波特率发生器高位
    SBRTH = 0xFF;
    // 波特率发生器低位
    SBRTL = 0x64;
    // 波特率发生器微调
    SFINE = 0x04;
    // 使能串口中断
    IEN0 |= 0x10;
}

/**
 * @brief 发送缓冲区数据
 */
static void Uart0_Transmit(void) {
    ptr_tx0 = &gUart0DataTxD[0];
    SBUF = *ptr_tx0;
    if (gUart0Len_TxD > 0)
        gUart0Len_TxD--;
    ptr_tx0++;
}

/**
* @brief 发送一个字节
*/
void Uart0_Send_Byte(U8 byte) {
    Uart0_Send_Bytes(&byte, 1);
}

/**
 * @brief 发送数组
 * @param bytes
 * @param len
 */
void Uart0_Send_Bytes(const U8 *bytes, U8 len) {
    memcpy(gUart0DataTxD, bytes, len);
    gUart0Len_TxD = len;
    Uart0_Transmit();
}

/**
 * @brief 发送字符串
 * @param str
 * @param len
 */
void Uart0_Send_String(const char *str) {
    U8 len = strlen(str);
    memcpy(gUart0DataTxD, str, len);
    gUart0Len_TxD = len;
    Uart0_Transmit();
}

/**
* @brief UART0中断
**/
void INT_EUART0(void) interrupt 4{
    if(TI){
        TI = 0;
        if(gUart0Len_TxD >0){
            SBUF = *ptr_tx0;
            gUart0Len_TxD --;
            ptr_tx0 ++;
        }
    }
}

本文学习资源参考中颖官方文档
本文代码开源地址: https://gitee.com/xundh/learn-sinowealth-51

  • 19
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程圈子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值