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