• 这篇文章适合已经有单片机基础,比如STM32。熟悉STM32库函数(标准库最好,HAL库要适应一下手写配置)
  • 这篇文章的代码均经过本人烧写验证,帮你快速上手HT32F52352
  • 如果觉得对你有帮助,记得点赞(别老是放在收藏夹里吃灰)

更多有意思的文章点击“我的主页”
--------😐
更多有意思的视频 -----> B站 @想要亿只独角兽
--------😐


目录

一、软硬件介绍

二、代码

2.1.  简单的GPIO高低电平,上下拉电阻,方向,输出电流大小控制(点灯)

GPIO.c

 GPIO.h

2.2.  串口

 USART0.c

 USART0.h

接收发送

串口打印 printf scanf

蓝牙

2.3. 定时器中断

BFTM(BASIC)基本配置

BFTM 中断函数

GPTM(通用)基本配置

GPTM 中断函数

2.4. PWM

定时器及GPIO配置

2.5. 延时函数delay

delay.c

delay.h

2.6. EXTI

exti.c

外部中断函数

 三、总结


一、软硬件介绍

  • 软件:MDK5   HT32 CodeConfig

 

  • 硬件:HT32F52352最小系统板

最小系统板采用立创专业版绘制,感兴趣的朋友可以到 闲鱼店铺:黄金独角兽的小店 了解

最小系统板原理图和PCB购买链接https://m.tb.cn/h.UH348hk?tk=kXWidPiDCNn

实物视频演示 :

自制合泰HT32F52352最小系统板(#合泰杯)


二、代码

2.1.  简单的GPIO高低电平,上下拉电阻,方向,输出电流大小控制(点灯)

  • GPIO.c

#include "GPIO.h"

void GPIO_Configuration(void)
{
  CKCU_PeripClockConfig_TypeDef CKCUClock = {{ 0 }};
  CKCUClock.Bit.Px    = 1; 
  CKCU_PeripClockConfig(CKCUClock, ENABLE);

  GPIO_SetOutBits         (HT_GPIOx, GPIO_PIN_x); // 初始高电平
  //GPIO_ClearOutBits        (HT_GPIOx, GPIO_PIN_x); // 初始低电平
  GPIO_DirectionConfig    (HT_GPIOx, GPIO_PIN_x, GPIO_DIR_OUT); // 输入输出方向 @arg GPIO_DIR_IN  @arg GPIO_DIR_OUT
  GPIO_PullResistorConfig (HT_GPIOx, GPIO_PIN_x, GPIO_PR_DISABLE); //上拉下拉电阻 @arg GPIO_PR_UP @arg GPIO_PR_DOWN @arg GPIO_PR_DISABLE
  GPIO_DriveConfig        (HT_GPIOx, GPIO_PIN_x, GPIO_DV_8MA); //输出电流大小 4,8,12,16

 //GPIO_InputConfig(HT_GPIOx, GPIO_PIN_x, ENABLE);    //此函数可实现GPIO口变为输入模式,上拉电阻,默认电流。
}
  •  GPIO.h

#ifndef __GPIO_H__
#define __GPIO_H__

//-----------------------------------------------------------------------------
#include "ht32.h"
//-----------------------------------------------------------------------------
void GPIO_Configuration(void);
//-----------------------------------------------------------------------------
#endif

  • 运用代码

GPIO_WriteOutBits(HT_GPIOx,GPIO_PIN_x,RESET) // SET or RESET


2.2.  串口

这一部分分为基本的串口配置,串口打印 以及 蓝牙(蓝牙有些问题,原理没错但当时没有反应)

  •  USART0.c

#include "USART0.h"

void USART0_Configuration(void)
{
  USART_InitTypeDef USART_InitStruct; // 声明结构体
  
  CKCU_PeripClockConfig_TypeDef CKCUClock = {{0}};
  CKCUClock.Bit.USART0   = 1;
  CKCUClock.Bit.AFIO     = 1;
  CKCUClock.Bit.PA      = 1;
  CKCU_PeripClockConfig(CKCUClock, ENABLE);
  // PA2--Tx  PA3--Rx
  AFIO_GPxConfig(GPIO_PA, AFIO_PIN_2, AFIO_MODE_6);  // 开启复用功能  AFIO_FUN_USART_UART
  AFIO_GPxConfig(GPIO_PA, AFIO_PIN_3, AFIO_MODE_6);  

  GPIO_PullResistorConfig(HT_GPIOA, GPIO_PIN_3, GPIO_PR_UP);  // 打开UxART Rx内部上拉电阻以防止未知状态 
      
  USART_InitStruct.USART_BaudRate = 115200;  // 波特率
  USART_InitStruct.USART_WordLength = USART_WORDLENGTH_8B; // 字节长度
  USART_InitStruct.USART_StopBits = USART_STOPBITS_1; // 停止位
  USART_InitStruct.USART_Parity = USART_PARITY_NO; // 校验位
  USART_InitStruct.USART_Mode = USART_MODE_NORMAL; // 模式
  USART_Init(HT_USART0, &USART_InitStruct); 
  
 
  
  //USART_IntConfig(HT_USARTx, USART_INT_RXDR ,ENABLE or DISABLE) // 接收数据就绪中断使能
  //USART_IntConfig(HT_USARTx, USART_INT_TXDE ,ENABLE or DISABLE) // 发送数据空中断使能   
  //NVIC_EnableIRQ(USART0_IRQn); // 初始化中断

  USART_RxCmd(HT_USART0, ENABLE); // 使能USART接收、发送 
  USART_TxCmd(HT_USART0, ENABLE);

  
}
  •  USART0.h

#ifndef __USART0_H__
#define __USART0_H__


//-----------------------------------------------------------------------------
#include "ht32.h"

//-----------------------------------------------------------------------------
void USART0_Configuration(void);

//-----------------------------------------------------------------------------
#endif

  • 接收发送

/**************************实现函数********************************************
函数说明:接收中断服务函数
*******************************************************************************/ 
void USARTx_IRQHandler(void)
{
  u8 data;
  if( USART_GetFlagStatus(HT_USARTx, USART_FLAG_RXDR) ) // 接收器 FIFO 就绪标志位
    {                                                                                                                                                                                    
     data = USART_ReceiveData(HT_USARTx); // 接收数据时已经自动清除中断标志位了,不用手动清除。      
    }
                
}


/**************************实现函数********************************************
函数说明:发送数组

*******************************************************************************/ 
void USART_Tx(const char* TxBuffer, u32 length)
{
  int i;

  for (i = 0; i < length; i++)
  {
    while (USART_GetFlagStatus(HT_USARTx, USART_FLAG_TXC) == RESET); // 判断是否 发送完成
    USART_SendData(HT_USARTx, TxBuffer[i]);
    //while (USART_GetFlagStatus(HT_USARTx, USART_FLAG_TXDE) == RESET); // 判断是否 发送完成
  }
}

  • 串口打印 printf scanf

// 这部分可以直接加到配置代码里
/*
 重定向时还需要注意一定要把printf.c里的signed int printf(const char *f, ...)、signed int puts(const char *pString)
 以及ht32_retarget.c里的int fputc (int ch, FILE *f)、int fgetc (FILE *f) 注释掉 
*/


//重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
  while (USART_GetFlagStatus(HT_USART1, USART_FLAG_TXC) == RESET);
  USART_SendData(HT_USART1, ch);
  return ch;
}
 
// 重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
    /* 等待串口输入数据 */
    while (USART_GetFlagStatus(HT_USARTx, USART_FLAG_RXDNE) == RESET);
 
    return (int)USART_ReceiveData(HT_USARTx);
 }
 

  • 蓝牙

// 存在一些问题,用串口助手发送数据包单片机可以接收,但是同样的代码用蓝牙就不行,代码应该是没问题的

/*********************** .c 文件中添加 **********************************/

uint8_t USART0_RX_BUF[USART0_REC_LEN]; // 接收缓冲,最大USART_REC_LEN个字节
uint16_t USART0_RX_STA=0; // 接收状态标记//bit15:接收完成标志,bit14~0:接收到的有效字节数目
uint8_t USART0_NewData; // 当前串口中断接收的1个字节数据的缓存

void USART0_IRQHandler(void)
{
    if(USART_GetIntStatus(HT_USART0, USART_INT_RXDR ) == SET ) // 接收器 FIFO 就绪标志位 USART_FLAG_RXDR  USART_FLAG_RXDNE
    {
        USART0_NewData = USART_ReceiveData(HT_USART0); // 接收数据时已经自动清除中断标志位了,不用手动清除
        
        if( (USART0_RX_STA&0x8000)==0 ) // 接收未完成
        {            
            if(USART0_NewData==0x5A) // 接收到了0x5A
            {
                USART0_RX_STA|=0x8000;   // 接收完成了,将USART2_RX_STA中的bit15(15位)置1     
            }
            else
            {
                USART0_RX_BUF[USART0_RX_STA&0X7FFF]=USART0_NewData;
                USART0_RX_STA++;  // 数据长度计数加1
                if( USART0_RX_STA>(USART0_REC_LEN-1) ) USART0_RX_STA=0;// 接收数据错误,重新开始接收
                
            } 
        }
    }

}


/*********************** .h 文件中添加 **********************************/
#define USART0_REC_LEN  200//定义USART2最大接收字节数

extern uint8_t  USART0_RX_BUF[USART0_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为校验和
extern uint16_t USART0_RX_STA;//接收状态标记
extern uint8_t USART0_NewData;//当前串口中断接收的1个字节数据的缓存


/*********************** main.c 中添加 **********************************/

        if(USART0_RX_STA&0x8000)              //判断中断接收标志位(蓝牙模块使用USART0)
        {
         if( (USART0_RX_STA&0x7FFF) == 3     // 判断接收数量3个                    
                && USART0_RX_BUF[0]==0xA5       // 判断接收第1个数据是不是包头0xA5
                && USART0_RX_BUF[2]==(USART0_RX_BUF[1])%0x100)      // 判断接收校验码是不是原数据之和的低8位
         {
             switch(USART0_RX_BUF[1])     //接收并读取蓝牙发送过来的第2个数据
             {
             case 0x01:  GPIO_WriteOutBits(HT_GPIOA,GPIO_PIN_0,SET);  break;
             case 0x02:  GPIO_WriteOutBits(HT_GPIOA,GPIO_PIN_1,SET);  break;
//             case 0x03:  GPIO_WriteOutBits(HT_GPIOA,GPIO_PIN_1,SET);  break;
//             case 0x04:  GPIO_WriteOutBits(HT_GPIOA,GPIO_PIN_1,RESET);  break;
             case 0x00:  GPIO_WriteOutBits(HT_GPIOA,GPIO_PIN_0|GPIO_PIN_1,RESET);  break; 
             default:  break;

             }
         }
         USART0_RX_STA=0;//标志位清0,准备下次接收
        }

2.3. 定时器中断

  • BFTM(BASIC)基本配置

BFTM0.c

#include "BFTM0.h"
#define BFTM0_TIMER_BASE            ((long long)SystemCoreClock * 100/1000) // SystemCoreClock/1000 == 1ms , SystemCoreClock /1000000 == 1us

void BFTM0_Configuration(void)
{
  CKCU_PeripClockConfig_TypeDef CKCUClock = {{ 0 }};
  CKCUClock.Bit.BFTM0      = 1;
  CKCU_PeripClockConfig(CKCUClock, ENABLE);

  BFTM_SetCounter(HT_BFTM0, 0);
  BFTM_SetCompare(HT_BFTM0, BFTM0_TIMER_BASE); 
 
  BFTM_ClearFlag(HT_BFTM0); // 清除中断标志位     
  BFTM_IntConfig(HT_BFTM0, ENABLE); // 开启 BFTM interrupt
  NVIC_EnableIRQ(BFTM0_IRQn);   

  BFTM_EnaCmd(HT_BFTM0, ENABLE); // 开启基础定时器BFTM
}

BFTM0.h

#ifndef __BFTM0_H__
#define __BFTM0_H__

//-----------------------------------------------------------------------------
#include "ht32.h"
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
void BFTM0_Configuration(void);
//-----------------------------------------------------------------------------
#endif

  • BFTM 中断函数

void BFTM0_IRQHandler(void)
{
  if(BFTM_GetFlagStatus(HT_BFTM0) == SET)
  {
      BFTM_ClearFlag(HT_BFTM0); // 清除中断标志位    

      //add code here
      
  }
}

  • GPTM(通用)基本配置

( MCTM\SCTM一样用法)


void GPTM0_Configuration(void)
{
  TM_TimeBaseInitTypeDef TM_TimeBaseInitStruct;  // 声明结构体
  CKCU_PeripClockConfig_TypeDef CKCUClock = {{ 0 }};
  CKCUClock.Bit.GPTM0      = 1;
  CKCU_PeripClockConfig(CKCUClock, ENABLE);
  
  TM_TimeBaseInitStruct.Prescaler = wPSCR; // 预分频系数
  TM_TimeBaseInitStruct.CounterReload = wCRR; // 计数周期
  TM_TimeBaseInitStruct.RepetitionCounter = 0;
  TM_TimeBaseInitStruct.CounterMode = TM_CNT_MODE_UP; // 计数模式
  TM_TimeBaseInitStruct.PSCReloadTime = TM_PSC_RLD_IMMEDIATE;// 立即重装载  
  TM_TimeBaseInit(HT_GPTM0, &TM_TimeBaseInitStruct);  
  
  TM_ClearIntPendingBit(HT_GPTM0, TM_INT_UEV); // 清除中断标志位     
  TM_IntConfig(HT_GPTM0, TM_INT_UEV, ENABLE); //开启GPTM0定时器中断
  NVIC_EnableIRQ(GPTM0_IRQn);   

  TM_Cmd(HT_GPTM0, ENABLE); // 开启GPTM0
}
  • GPTM 中断函数

void GPTM0_IRQHandler(void)
{
  if( TM_GetIntStatus(HT_GPTM0, TM_INT_UEV) ==SET ) // 判断定时器更新中断 是否发生  TM_GetFlagStatus (HT_GPTM0,  TM_FLAG_UEV) 
  {
      TM_ClearIntPendingBit(HT_GPTM0, TM_INT_UEV );      

      //add code here
  
                    
  }    
}


2.4. PWM

PWM的配置需要配置定时器以及配置复用的GPIO(把定时器通道对应的gpio设置成输出方向)

  • 定时器及GPIO配置

GPTM0.c

#include "GPTM0.h"
void GPTM0_Configuration(void)
{  

  TM_TimeBaseInitTypeDef TM_TimeBaseInitStruct; // 声明结构体
  TM_OutputInitTypeDef TM_OutputInitStruct;
  
  CKCU_PeripClockConfig_TypeDef CKCUClock = {{ 0 }};
  CKCUClock.Bit.GPTM0      = 1;
  CKCUClock.Bit.AFIO       = 1;
  CKCUClock.Bit.PA    = 1;
  CKCU_PeripClockConfig(CKCUClock, ENABLE); // 时钟使能  
  AFIO_GPxConfig(GPIO_PA, AFIO_PIN_4, AFIO_MODE_4 );  // 开启复用功能 AFIO_FUN_PWM 
  
  GPIO_DirectionConfig    (HT_GPIOx, GPIO_PIN_x, GPIO_DIR_OUT); // 输入输出方向 @arg GPIO_DIR_IN  @arg GPIO_DIR_OUT
  TM_OutputStructInit(&TM_OutputInitStruct);    //填写 TM_OutputInit 每个成员的默认值
  
  // 定时器时基以及计数方式初始化
  TM_TimeBaseInitStruct.Prescaler = wPSCR; // 预分频系数
  TM_TimeBaseInitStruct.CounterReload = wCRR; // 计数周期
  TM_TimeBaseInitStruct.RepetitionCounter = 0;
  TM_TimeBaseInitStruct.CounterMode = TM_CNT_MODE_UP; // 计数模式
  TM_TimeBaseInitStruct.PSCReloadTime = TM_PSC_RLD_IMMEDIATE;// 立即重装载  
  TM_TimeBaseInit(HT_GPTM0, &TM_TimeBaseInitStruct);  

  // 通道及输出模式初始化
  TM_OutputInitStruct.Channel = TM_CH_0; //选择通道
  TM_OutputInitStruct.OutputMode = TM_OM_PWM1; //PWM模式
  TM_OutputInitStruct.Control = TM_CHCTL_ENABLE; // GPTM通道使能
  TM_OutputInitStruct.Polarity = TM_CHP_NONINVERTED; // 通道极性,@arg TM_CHP_INVERTED是低电平或下降沿  @arg TM_CHP_NONINVERTED是上升沿
  TM_OutputInit(HT_GPTM0, &TM_OutputInitStruct);
  
  TM_Cmd(HT_GPTM0, ENABLE); //开启GPTM0
}

GPTM0.h

#ifndef __GPTM0_H__
#define __GPTM0_H__

//-----------------------------------------------------------------------------
#include "ht32.h"
//-----------------------------------------------------------------------------
void GPTM0_Configuration(void);
//-----------------------------------------------------------------------------
#endif

PWM运用代码

TM_SetCaptureCompare0(HT_GPTM0, cmp); //设置占空比,TM_SetCaptureCompare后的0表示通道0

2.5. 延时函数delay

  • delay.c

ms级

#include "delay.h"
 
void Delay_ms(u32 ms)
{
    u32 i;
    
    /* SYSTICK configuration */
    SYSTICK_ClockSourceConfig(SYSTICK_SRC_STCLK);       // 即默认选择了外部参考时钟
    SYSTICK_SetReloadValue(SystemCoreClock / 8 / 1000); // (CK_SYS/8/1000) = 1ms 
    SYSTICK_IntConfig(DISABLE);                         // 不开启中断
 
    /* 打开SysTick计数器 */
    SYSTICK_CounterCmd(SYSTICK_COUNTER_CLEAR);
    SYSTICK_CounterCmd(SYSTICK_COUNTER_ENABLE);
    
    for( i = 0;i < ms;i++ )
    {
        while( !( (SysTick->CTRL) & (1<<16) ) ); 
    }
 
    /* 关闭SysTick计数器 */
    SYSTICK_CounterCmd(SYSTICK_COUNTER_DISABLE);
    /* 复位SysTick计数器 */
    SYSTICK_CounterCmd(SYSTICK_COUNTER_CLEAR);
}
 

us级

void Delay_us(u32 us)
{
    u32 i;
    
    /* SYSTICK configuration */
    SYSTICK_ClockSourceConfig(SYSTICK_SRC_STCLK);       // 即默认选择了外部参考时钟
    SYSTICK_SetReloadValue(SystemCoreClock / 8 / 1000000); // (CK_SYS/8/1000000) = 1us 
    SYSTICK_IntConfig(DISABLE);                         // 不开启中断
 
    /* 打开SysTick计数器 */
    SYSTICK_CounterCmd(SYSTICK_COUNTER_CLEAR);
    SYSTICK_CounterCmd(SYSTICK_COUNTER_ENABLE);
 
    for( i = 0;i < us;i++ )
    {
        while( !( (SysTick->CTRL) & (1<<16) ) ); 
    }
 
    /* 关闭SysTick计数器 */
    SYSTICK_CounterCmd(SYSTICK_COUNTER_DISABLE);
    /* 复位SysTick计数器 */
    SYSTICK_CounterCmd(SYSTICK_COUNTER_CLEAR);
}

  • delay.h

#ifndef __DELAY_H
#define __DELAY_H     

#include "ht32_cm0plus_misc.h"

void Delay_ms(u32 ms);
void Delay_us(u32 us);


#endif


2.6. EXTI

  • exti.c

#include "EXTI.h"

void EXTI_Configuration(void)
{
  EXTI_InitTypeDef EXTI_InitStruct = {0};
  CKCU_PeripClockConfig_TypeDef CKCUClock = {{ 0 }};
  CKCUClock.Bit.EXTI    = 1;
  CKCUClock.Bit.AFIO    = 1;
  CKCUClock.Bit.PC      = 1;   
  CKCU_PeripClockConfig(CKCUClock, ENABLE);

  AFIO_GPxConfig( GPIO_PC, AFIO_PIN_10, AFIO_FUN_GPIO);
  AFIO_EXTISourceConfig(AFIO_EXTI_CH_10,AFIO_ESS_PC); // 中断来源选择PC10
  GPIO_InputConfig(HT_GPIOC, GPIO_PIN_10, ENABLE);    // 此函数可实现GPIO口变为输入模式,上拉电阻,默认电流。
  
  EXTI_InitStruct.EXTI_Debounce = EXTI_DEBOUNCE_DISABLE; // 去抖
  EXTI_InitStruct.EXTI_DebounceCnt = 0;
  EXTI_InitStruct.EXTI_Channel = AFIO_EXTI_CH_10;  // EXTI_10
  EXTI_InitStruct.EXTI_IntType = EXTI_NEGATIVE_EDGE; // 下降沿触发
  EXTI_Init(&EXTI_InitStruct);
  
  EXTI_IntConfig(AFIO_EXTI_CH_10, ENABLE);
  NVIC_EnableIRQ(EXTI4_15_IRQn);
}

  • 外部中断函数

//---------- 外部中断函数-----------
void EXTI4_15_IRQHandler(void)
{
  if (EXTI_GetEdgeStatus(EXTI_CHANNEL_10, EXTI_EDGE_NEGATIVE))
  {
    EXTI_ClearEdgeFlag(EXTI_CHANNEL_10);
    //add code here
  }

  }


 三、总结

是不是和STM32的标准库很像。。。学习了合泰之后明显感觉他的库的注释不是很友好,很多功能以及规范确实不如STM32好上手。

一开始的那个软件 HT32 CodeConfig 这个是合泰官方自己开发的类似CubeMX的软件,很容易上手,并且我认为这个开发软件可以更快地帮助我们上手HT32。我把这个软件和初始工程的网盘链接放在下方和CSDN仓库里(有积分的可以支持一下)


  •  HT32 CodeConfig 以及HT的串口烧录软件:

链接:https://pan.baidu.com/s/1HjtJDCpDI_-UZxXsp5dyCg?pwd=f7f3 
提取码:f7f3

  • 初始工程:

链接:https://pan.baidu.com/s/1yONcXJb4uU0d0dt0UZFndQ?pwd=h27p 
提取码:h27p


欢迎大家积极交流,本文未经允许谢绝转载!!!

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐