头图

前言
大家好,我是棒棒糖,在上一期我们主要介绍了关于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的中断发送接收数据,如果有需要工程的小伙伴可以私信我,我们下一期见。


爱玩的棒棒糖
1 声望0 粉丝