GPIO
名称 | 功能 |
GPIO_PIN_RESET |
低电平(0) |
GPIO_PIN_SET |
高电平(1) |
定时器
us延时函数实现:
HAL库:
/**************************************没有操作系统**********************************/
static uint16_t g_fac_us = 0; /* us延时倍乘数 */
/**
* @brief 初始化延迟函数
* @param sysclk: 系统时钟频率, 即CPU频率(HCLK)
* @retval 无
*/
void delay_init(uint16_t sysclk) //例如:g_fac_us = 72 / 8
{
SysTick->CTRL = 0; /* 清Systick状态,以便下一步重设,如果这里开了中断会关闭其中断 */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8); /* SYSTICK使用内核时钟源8分频,因systick的计数器最大值只有2^24 */
g_fac_us = sysclk / 8; /* g_fac_us作为1us的基础时基 */
}
/**
* @brief 延时nus
* @param nus: 要延时的us数.
* @note 注意: nus的值,不要大于1864135us(最大值即2^24 / g_fac_us @g_fac_us = 9)
* @retval 无
*/
void delay_us(uint32_t nus)
{
uint32_t temp;
SysTick->LOAD = nus * g_fac_us; /* 时间加载 */
SysTick->VAL = 0x00; /* 清空计数器 */
SysTick->CTRL |= 1 << 0 ; /* 开始倒数 */
do
{
temp = SysTick->CTRL;
} while ((temp & 0x01) && !(temp & (1 << 16))); /*判断temp的最低位(即CTRL.ENABLE位)是否为1,表示SysTick定时器使能;同时,判断temp的第16位是否为0,表示时间还未到达。*/
SysTick->CTRL &= ~(1 << 0) ; /* 关闭SYSTICK */
SysTick->VAL = 0X00; /* 清空计数器 */
}
/**
* @brief 延时nms
* @param nms: 要延时的ms数 (0< nms <= 65535)
* @retval 无
*/
void delay_ms(uint16_t nms)
{
uint32_t repeat = nms / 1000; /* 记录超出1000ms的值,即1s */
uint32_t remain = nms % 1000; /* 记录未超出1000ms的值 */
while (repeat)
{
delay_us(1000 * 1000); /* 利用delay_us 实现 1000ms 延时 */
repeat--;
}
if (remain)
{
delay_us(remain * 1000); /* 利用delay_us, 把尾数延时(remain ms)给做了 */
}
}
/*******************************************加入操作系统************************/
// 初始化定时器
void TIM_Init(void)
{
TIM_HandleTypeDef htim;
htim.Instance = TIM2;
htim.Init.Period = 0xFFFF;
htim.Init.Prescaler = HAL_RCC_GetPCLK1Freq() / 1000000 - 1; // 设置定时器时钟为1MHz
htim.Init.ClockDivision = 0;
htim.Init.CounterMode = TIM_COUNTERMODE_UP;
HAL_TIM_Base_Init(&htim);
}
// 微秒级延时函数
void Delay_us(uint32_t us)
{
__HAL_TIM_SET_COUNTER(&htim2, 0); // 清空定时器计数器
HAL_TIM_Base_Start(&htim2); // 启动定时器
while (__HAL_TIM_GET_COUNTER(&htim2) < us); // 等待定时器计数器达到指定值
HAL_TIM_Base_Stop(&htim2); // 停止定时器
}
标准库:
/********************************没有操作系统************************************/
static u8 fac_us = 0;
static u16 fac_ms = 0;
void delay_init(void)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); // 选择外部时钟 HCLK/8
fac_us = SystemCoreClock / 8000000;
fac_ms = (u16)fac_us * 1000;
}
void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD = nus * fac_us; // 延时时间加载
SysTick->VAL = 0x00; // 清空计数器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // 开始倒数
do
{
temp = SysTick->CTRL;
} while ((temp & 0x01) && !(temp & (1 << 16))); // 等待时间到达
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // 关闭计数器
SysTick->VAL = 0x00; // 清空计数器
}
void delay_ms(u16 nms)
{
u32 temp;
SysTick->LOAD = (u32)nms * fac_ms; // 时间加载(SysTick->LOAD为24bit)
SysTick->VAL = 0x00; // 清空计数器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // 开始倒数
do
{
temp = SysTick->CTRL;
} while ((temp & 0x01) && !(temp & (1 << 16))); // 等待时间到达
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // 关闭计数器
SysTick->VAL = 0x00; // 清空计数器
}
/*********************************加入操作系统************************************/
void TIM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // Enable the clock for TIM2
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / 1000000 - 1; // Set timer clock to 1MHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_Cmd(TIM2, ENABLE); // Enable TIM2
}
void Delay_us(uint32_t us)
{
TIM_SetCounter(TIM2, 0); // Clear the timer counter
while (TIM_GetCounter(TIM2) < us); // Wait until the timer counter reaches the specified value
}
标准库:
需要使能TIM_Cmd(TIM8, ENABLE); 和 TIM3_IRQHandler中断服务函数
HAL库:
要手动开启和关闭定时器及其中断:
HAL_StatusTypeDef HAL_TIM_Base_Stop(TIM_HandleTypeDef *htim)
HAL_StatusTypeDef HAL_TIM_Base_Stop(TIM_HandleTypeDef *htim)
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)
HAL_StatusTypeDef HAL_TIM_Base_Stop_IT(TIM_HandleTypeDef *htim)
中断回调函数 -- 名字不能错误 && 一定要先开定时器中断,再开定时器
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim == &htimx)
{
}
}
PWM输出通道
单路输出
标准库:
开启 TIM_CtrlPWMOutputs(TIM8, ENABLE);
设置比较值 TIM_SetCompare1(TIM8, pwm);
HAL库:
开启
HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
设置比较值(设置占空比)
__HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__)
互补输出
高级定时器特有,电机控制常用。分频和单路相同
DMA模式
开启DMA
HAL_StatusTypeDef HAL_TIM_PWM_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData, uint16_t Length)
关闭DMA
DMA中断里调用,不然可能出现少了脉冲
HAL_StatusTypeDef HAL_TIM_PWM_Stop_DMA(TIM_HandleTypeDef *htim, uint32_t Channel)
PWM+DMA中断回调函数
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
if (htim == &htimx)
{
}
}
从内存到外设 普通模式 建议设置为字(word)模式
外部中断
需要自己写,名字不能错误
标准库:
对GPIO进行EXTI和NVIC的配置,手写EXTI中断服务函数
HAL库:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == GPIO_PIN_x)
{
}
}
低功耗停止模式(STOP)
这个是最常用的低功耗模式 -- 由外部中断唤醒
标准库:
HAL库:
void stop_mode(void)
{
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);//清除标志
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);//进入停止模式
//这里放HAL生成的那些初始化函数
}
退出停止模式后默认使用是内部RC震荡,系统频率可能会改变。懒人方法是将HAL库在main前面的初始化函数放到这个停止模式的后面即可,退出停止模式后回到这个地方继续执行
串口
阻塞模式
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
#define printf(...) \
HAL_UART_Transmit(&huart5,(uint8_t *)u_buf,sprintf((char *)u_buf,__VA_ARGS__),0xffff)
uint8_t u_buf[128];
中断模式
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == &huart1)
{
HAL_UART_Receive_IT(&huart1, &Uart_BUF, 1);
}
}
空闲中断(不定长数据接收)
当总线没有数据一段时间后,认为总线空闲,触发空闲中断
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
空闲中断回调函数
uint8_t BUF[100] = {0};
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if (huart == &huart2)
{
HAL_UARTEx_ReceiveToIdle_IT(&huart1,BUF,100);
}
}
建议使用空闲中断时,使用DMA模式发送数据
DMA模式
DMA发送
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)
DMA的初始化需要在UART之前
停止DMA发送
HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart)
DMA空闲接收 (有点复杂......)
实现的功能是 使用DMA接收数据,接收到超过指定数量时,或者数据接收完成(触发空闲状态)
SPI
IIC
硬件IIC:
#define ADDR_AT24C512_Write 0xA0
#define ADDR_AT24C512_Read 0xA1
int16_t AT24C512_Write_nBytes(uint8_t *data, uint16_t addr, uint16_t length)
{
if( HAL_I2C_Mem_Write( &hi2c1, ADDR_AT24C512_Write, addr, I2C_MEMADD_SIZE_16BIT, data, length, 1000 ) == HAL_OK )
return 0;
else
return -1;
}
int16_t AT24C512_Read_nBytes(uint8_t *data, uint16_t addr, uint16_t length)
{
if( HAL_I2C_Mem_Read( &hi2c1, ADDR_AT24C512_Write, addr, I2C_MEMADD_SIZE_16BIT, data, length, 1000 ) == HAL_OK )
return 0;
else
return -1;
}
CAN
术语定义
扩展帧 -- 规范中定义的使用 29 位标志符的 CAN 数据帧;
标准帧 -- 规范中定义的使用 11 位标识符的 CAN 数据帧;
数据域 -- 数据帧中包含应用层定义的 0-64 位数据;
ADC
阻塞查询
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc)
等待ADC转化完成
HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout)
(可选)关闭ADC
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef* hadc)
DMA模式
扫描模式开启(多通道)
ADC到内存(默认设置) 模式选择正常模式 内存地址自增,半字节文章来源:https://www.toymoban.com/news/detail-812939.html
ADC校准(在初始化函数之后,DMA调用之前) 文章来源地址https://www.toymoban.com/news/detail-812939.html
HAL_StatusTypeDef HAL_ADCEx_Calibration_Start(ADC_HandleTypeDef* hadc)
HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData,
中断回调函数
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
if (hadc == &hadcx)
{
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&Buf, 4);//如需多次采集则使用这句
}
}
软件复位
__set_FAULTMASK(1);//关中断
NVIC_SystemReset();//复位
到了这里,关于【STM32】常用功能备忘录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!