STM32常用功能备忘录 – 必备参考指南

 GPIO

GPIO_PinState
名称 功能

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到内存(默认设置)  模式选择正常模式  内存地址自增,半字节

ADC校准(在初始化函数之后,DMA调用之前) 

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();//复位

物联沃分享整理
物联沃-IOTWORD物联网 » STM32常用功能备忘录 – 必备参考指南

发表评论