【STM32】常用功能备忘录

目录

GPIO

定时器

us延时函数实现:

PWM输出通道

IO模拟

单路输出

开启

设置比较值(设置占空比)

互补输出

DMA模式 

开启DMA

关闭DMA

PWM+DMA中断回调函数

中断 

中断优先级与任务优先级区别

外部中断

低功耗停止模式(STOP)

串口

HAL库Printf打印

标准库printf

阻塞模式

中断模式

空闲中断(不定长数据接收)

DMA模式

DMA空闲接收 (有点复杂......)

串口中途死机

SPI

介绍

硬件spi 和 软件spi

IIC

介绍

软件IIC:

硬件IIC:

CAN 

术语定义

ADC

阻塞查询

DMA模式

DAC

软件复位

FREERTOS

消息队列

信号量

二值信号量

计数信号量

低功耗

FreeRTOS调试 

三种调度方式


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)给做了 */
		}
	}

	/*******************************************定时器延时 1************************/
	// 初始化定时器
	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;          // 清空计数器
}
	
	/*******************************************定时器延时 1************************/
	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
	}
	

/*******************************************定时器延时 2************************/
/*最精确*/
/**
    开启一个毫秒级定时器,等待时间到将flag复位
*/

volatile unsigned int delayFlag = 0;
  
/*
    us微妙级延时定时器初始化
*/
void DelayInit(void)
{
    /* -----------------------------------------------------------------------
	  系统主频120MHZ,timer_initpara.prescaler为11,timer_initpara.period为9,频率就为1MHZ
    ----------------------------------------------------------------------- */
    timer_parameter_struct timer_initpara;
    rcu_periph_clock_enable(RCU_TIMER1);
    timer_deinit(TIMER1);
    /* TIMER1 configuration */
    timer_initpara.prescaler         = 11;     
    timer_initpara.period            = 9;
    
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER1,&timer_initpara);
	nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
	nvic_irq_enable(TIMER1_IRQn, 0, 1);
	timer_interrupt_enable(TIMER1, TIMER_INT_UP);
    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIMER1);
    /* auto-reload preload enable */
   timer_enable(TIMER1);
    
}


void Delay_ms(u16 ms)
{
    delayFlag = ms * 1000;
    while(delayFlag);
}


void Delay_us(u32 nus)
{
   delayFlag = nus; 
    while(delayFlag);
}

void TIMER1_IRQHandler(void)
{
   timer_flag_clear(TIMER1,TIMER_FLAG_UP);
   if (0U != delayFlag){
        delayFlag--;
    }
}

标准库:

        需要使能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输出通道

        脉冲宽度可调制。 -- 使用地方:电机调速(直流电机、步进电机)、舵机、灯的亮度等等。         占空比:高电平 所占整个周期的比例
        当计数器值与比较寄存器值相等时,电平发生反转。
        有效电平自己设置:        假设:有效电平 = 高电平
        PWM1模式:计数器小于比较寄存器,输出有效电平
        PWM2模式:计数器小于比较寄存器,输出无效电平

IO模拟

//固定占空比(占空比可变) 放在中断中执行设置频率
#define PWM_PERIOD      1000            // PWM周期(单位:循环次数)
#define PWM_DUTY_CYCLE  500             // PWM占空比50%(单位:循环次数)

// 函数声明
void LED_Init(void); // 初始化LED引脚
void LED_Write(bool state); // 写入LED引脚状态

int main(void) {
    LED_Init(); // 初始化LED引脚

    while (1) {
        for (uint16_t i = 0; i < PWM_PERIOD; i++) {
            if (i < PWM_DUTY_CYCLE) {
                LED_Write(true); // LED引脚输出高电平
            } else {
                LED_Write(false); // LED引脚输出低电平
            }
        }
    }
}

void LED_Init(void) {
    // 初始化LED引脚为输出模式
    // 这里的实现取决于您的硬件平台
}

void LED_Write(bool state) {
    if (state) {
        // 将LED引脚设置为高电平
        // 这里的实现取决于您的硬件平台
    } else {
        // 将LED引脚设置为低电平
        // 这里的实现取决于您的硬件平台
    }
}

单路输出

         标准库:           

                        开启     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)模式

中断 

        NVIC_PriorityGroup_4        0-15级抢占优先级        0级子优先级

        4bit全用于抢占优先级 -- 0bit用于子优先级

中断优先级与任务优先级区别

        没有关系。中断的优先级永远高于任何任务的优先级,即任务在执行的过程中,中断来了就开始执行中断服务程序。

  • 23
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值