- 这篇文章适合已经有单片机基础,比如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文章来源:https://www.toymoban.com/news/detail-420872.html
欢迎大家积极交流,本文未经允许谢绝转载!!!文章来源地址https://www.toymoban.com/news/detail-420872.html
到了这里,关于合泰HT32F52352入门教程(# 1W+字 博客帮您快速上手,拿奖不是梦 #)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!