合泰HT32F52352入门教程(# 1W+字 博客帮您快速上手,拿奖不是梦 #)
- 这篇文章适合已经有单片机基础,比如STM32。熟悉STM32库函数(标准库最好,HAL库要适应一下手写配置)
- 这篇文章的代码均经过本人烧写验证,帮你快速上手HT32F52352
- 如果觉得对你有帮助,记得点赞(别老是放在收藏夹里吃灰)
更多有意思的文章点击“我的主页”
--------😐
更多有意思的视频 -----> B站 @想要亿只独角兽
--------😐
目录
2.1. 简单的GPIO高低电平,上下拉电阻,方向,输出电流大小控制(点灯)
一、软硬件介绍
- 软件: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
欢迎大家积极交流,本文未经允许谢绝转载!!!
更多推荐
所有评论(0)