家庭能源网关开发历程(三)JSY-MK-163串口中断发送接收

 前言

        大家好,我是菜菜,在上一期我们主要介绍了关于JSY-MK-163串口通讯配置流程。由于上期没有打印结果,我怕有一些小伙伴还是不懂,本期我们就来实现项目主控MCU华大HC32F005的UART中断发送和接收数据的结果打印。首先,我们先看看用到UART的那些功能函数。

UART功能函数

UART发送

 1.以查询的方式发送数据。

en_result_t Uart_SendDataPoll(M0P_UART_TypeDef* UARTx, uint8_t u8Data)
{
    UARTx->SBUF_f.SBUF = u8Data;
    while(FALSE == Uart_GetStatus(UARTx,UartTC))
    {}
    Uart_ClrStatus(UARTx,UartTC);       
    return Ok;
}

 2.以中断的方式发送数据

en_result_t Uart_SendDataIt(M0P_UART_TypeDef* UARTx, uint8_t u8Data)
{ 
    UARTx->SBUF_f.SBUF = u8Data; 
    
    return Ok;
}

         注:本期我们讲的是中断发送,所以等下我们调用的是该方式发送数据。

 UART接收

1.uart接收数据功能函数

uint8_t Uart_ReceiveData(M0P_UART_TypeDef* UARTx)
{
    return (UARTx->SBUF_f.SBUF);
}

 UART中断发送接收流程

uart发送单个

//串口发送字节(查询方式)
void UART1_SendByte(uint8_t  Data)
{
	Uart_SendDataPoll(M0P_UART1, Data);                                  
}

uart发送一串 

//串口发送一串
void UART1_SendString(char *u8Data)
{	
	int k=0;
while(*(u8Data+k)!='\0') 
		{
	Uart_SendDataPoll(M0P_UART1, *(u8Data+k));  
		k++;		  
		}
}

uart发送数组

//串口发送数组
void UART1_Sendarr(uint8_t * data,uint32_t len)
{
	uint32_t i=0;
	for(i=0;i<len;i++){
		UART1_SendByte(*data);
		data++;
	}
}

uart接收数据

//串口接收字节
uint8_t Uart_ReceByte(uint8_t *data)
{
	if(Uart_GetStatus(M0P_UART1, UartRC)==SET)         //UART1数据发送
    {  
		Uart_ClrStatus(M0P_UART1,UartRC);
		data[0]=Uart_ReceiveData(M0P_UART1);	
		return 1;
	}
	return 0;	
}

 首先,我们先定义一个结构,用于发送和接收多个数据准备。

typedef struct {
	uint8_t rbuf[11];
	uint16_t rcnt;
	uint8_t tbuf[11];
	uint16_t tcnt;
	uint16_t txp;
}com_type;

 接着写发送数据函数

com_type com_1 = {0};
// 使用中断方式发送数据的函数
void fnUart_SendIR(void){
    // 如果发送指针txp小于发送计数tcnt,说明还有数据未发送
    if(com_1.txp < com_1.tcnt){
        // 使用中断服务发送当前指针指向的数据
        Uart_SendDataIt(M0P_UART1, com_1.tbuf[com_1.txp]);
        // 更新发送指针,使用取模运算确保指针在0-255之间循环
        com_1.txp = (com_1.txp + 1) % 256;
    } else {
        // 如果所有数据已发送,重置发送指针
        com_1.txp = 0;
        // 禁用UART1的发送中断(这里是为了让串口实现半双工发送接收数据)
        Uart_DisableIrq(M0P_UART1, UartTxIrq);
    }
}

 获取发送的数据

// 获取已接收到的数据长度的函数
uint16_t fnUart_GETReadIR_BUF(void){
    uint16_t len;
    // 读取当前接收计数器的值,该值表示已接收数据的长度
    len = com_1.rcnt;
    // 重置接收计数器,为下一次接收做准备
    com_1.rcnt = 0;
    // 返回接收到的数据长度
    return len;
}

 设置要发送的数据长度

// 设置要发送的数据长度的函数
void fnUart_SendIR_BUF(uint16_t len){
    // 设置发送计数器为要发送的数据长度
    com_1.tcnt = len;
    // 重置发送指针,准备从头开始发送数据
    com_1.txp = 0;
    // 启用UART1的发送中断,开始发送数据
    Uart_EnableIrq(M0P_UART1, UartTxIrq);
    // 调用发送函数,开始发送数据
    fnUart_SendIR();
}

 设置复制函数

//复制功能函数
void fnmemcpy(uint8_t *srt,uint8_t *det,uint16_t len){
uint16_t i;
	for(i=0; i<len; i++){ det[i]=srt[i];}
}

 设置接收缓冲区

//接收缓冲区
uint8_t rec_buf[100];
uint16_t cnt1=0;
void fninputbuf(uint8_t dat){
	rec_buf[cnt1]=dat; // 将数据存储在当前位置
	cnt1=(cnt1+1)%100; // 更新数据,使用取模运算实现缓冲
}

 设置接收函数

//接收函数
void fncoming(void){
uint8_t temp;
	// 尝试从串口接收一个字节,如果失败则返回
	if(0==Uart_ReceByte(&temp)){return;}
	fninputbuf(temp);
	UART1_SendByte(temp); 
}

最后就是主函数的调用

int main(void)
{
uint16_t x;
	App_PortInit();
	SystemClock_Init();
	UartBaudCfg_Init();
//	GX30_I2C_Init();
    while(1) {
		fncoming();
		delay1ms(100);
		x=fnUart_GETReadIR_BUF();
		fnmemcpy(com_1.rbuf,com_1.tbuf,x);
		fnUart_SendIR_BUF(x);
	}
}

打印结果 

1.结果乱码

根据上面的流程,我们明明可以实现了串口中断的发送和接收数据,但是你会发现接收到的数据是乱的,这是怎么回事?

2.解决方法

        原来啊,是我们漏了一个比较重要的流程没有配置,那就是HC32F005要配置时钟。我们又回过头来配置时钟。

 时钟配置

//系统时钟配置
static void App_ClkCfg(void)
{
    stc_sysctrl_clk_cfg_t stcCfg;
   ///< 开启FLASH外设时钟
    Sysctrl_SetPeripheralGate(SysctrlPeripheralFlash, TRUE);
    ///< 因要使用的时钟源HCLK小于24M:此处设置FLASH 读等待周期为0 cycle(默认值也为0 cycle)
    Flash_WaitCycle(FlashWaitCycle0);

    ///< 时钟初始化前,优先设置要使用的时钟源:此处设置RCH为4MHz(默认值为4MHz)
    Sysctrl_SetRCHTrim(SysctrlRchFreq4MHz);

    ///< 选择内部RCH作为HCLK时钟源;
    stcCfg.enClkSrc = SysctrlClkRCH;
    ///< HCLK SYSCLK/2
    stcCfg.enHClkDiv = SysctrlHclkDiv1;
    ///< PCLK 为HCLK/8
    stcCfg.enPClkDiv = SysctrlPclkDiv1;
    ///< 系统时钟初始化
    Sysctrl_ClkInit(&stcCfg);
}

 设置频率

//将时钟从RCH4MHz切换至RCH24MHz,
void App_Rch4MHzTo24MHz(void)
{
    ///<============== 将时钟从RCH4MHz切换至RCH24MHz ==============================
    ///< RCH时钟不同频率的切换,需要先将时钟切换到RCL,设置好频率后再切回RCH
    Sysctrl_SetRCLTrim(SysctrlRclFreq32768);
    Sysctrl_ClkSourceEnable(SysctrlClkRCL, TRUE);
    Sysctrl_SysClkSwitch(SysctrlClkRCL);

    ///< 加载目标频率的RCH的TRIM值
    Sysctrl_SetRCHTrim(SysctrlRchFreq24MHz);
    ///< 使能RCH(默认打开,此处可不需要再次打开)
   // Sysctrl_ClkSourceEnable(SysctrlClkRCH, TRUE);
    ///< 时钟切换到RCH
    Sysctrl_SysClkSwitch(SysctrlClkRCH);
    ///< 关闭RCL时钟
    Sysctrl_ClkSourceEnable(SysctrlClkRCL, FALSE);
}

时钟初始化

void SystemClock_Init(void) //华大单片机严格按照规格书切换时钟
{

    App_ClkCfg();
    delay1ms(10);
    App_Rch4MHzTo24MHz();
     delay1ms(10);
    SystemCoreClockUpdate();
    delay1ms(10);
}

         最后,我们在主函数调用就可以解决乱码的问题啦,如下图是配置时钟之后的打印结果:

总结 

        到这里我们就完全实现了HC32F005的中断发送接收数据,如果有需要工程的小伙伴可以私信我,我们下一期见。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值