STM32杂项

STM32杂项

记录单片机在工作中遇到的问题和特殊情况。

1.启动过程

M3/M4/M7内核复位后,做的第一件事:

1.从地址0x0000 0000处取出++堆栈指针MSP的初始值++ ,该值就是栈顶地址

2.从地址0x0000 0004处取出++程序计数器PC的初始值++ ,该值是复位向量

在系统复位后,SYSCLK的第4个上升沿,BOOT引脚的值将被锁存。

2.中断

NVIC-管理中断;

EXTI-外部中断控制器;

中断:打断CPU执行正常的程序,转而处理紧急程序,然后返回原暂停的程序继续运行。

中断向量表:

定义一块固定的内存,以4字节对齐,存放各个中断服务函数程序的首地址。

中断向量表定义在++启动文件++ ,当发生中断,CPU会自动执行对应的中断服务函数。

NVIC相关寄存器:

抢占优先级(pre):高优先级可以打断正在执行的低抢占优先级中断。

响应优先级(sub):当抢占优先级相同时,响应优先级高的先执行,但不能相互打断。

抢占和响应都相同的情况下,自然优先级越高的,先执行。

自然优先级:中断向量表中的优先级。

数字越小,表示优先级越高。

分组:

优先级分组 分配结果
0 0位抢占优先级,4位响应优先级
1 1位抢占优先级,3位响应优先级
2 2位抢占优先级,2位响应优先级
3 3位抢占优先级,1位响应优先级
4 4位抢占优先级,0位响应优先级

一个工程中,一般只设置一次中断优先级分组。多次的话,以最后一次为准。

3.GPIO

工作电压范围:2V<VDD<3.6V。

识别电压范围:

低电压:-0.3V<V<1.164V。

高电压:1.833V<V<3.6V。

输出电流:单个IO,最大25MA。

类型:电源引脚,晶振引脚,复位引脚,下载引脚,BOOT引脚,GPIO引脚。

4.Systick

systick:系统滴答定时器,包含在M3/M4/M7内核里面,核心是一个24位的递减计数器。
72mhz经过分频器(CLKSOURCE),每来一个时钟,VAL自动减1,当VAL减到0时,COUNTFLAG变成1(可以判断这位是否为1,来判断是否到达延时时间,退出等待),并且LOAD的值自动赋给VAL重新开始计时。

其中VAL和LOAD的值为2的24次方(0~16777215)。

以下是不同的几种延时函数的写法:

c 复制代码
/*
第一种写法:不需要进行延时初始化,每执行一遍Delay_us()
相当于配置一遍滴答定时器,等待COUNTFLAG变成1。当不在调
用延时函数时停止滴答定时器。
*/
void Delay_us(uint32_t xus)
{
	SysTick->LOAD = 72 * xus;				//设置定时器重装值 2的24次方 16777216
	SysTick->VAL = 0x00;					//清空当前计数值
	SysTick->CTRL = 0x00000005;				//设置时钟源为HCLK,启动定时器
	while(!(SysTick->CTRL & 0x00010000));	//等待计数到0
	SysTick->CTRL = 0x00000004;				//关闭定时器
}
void Delay_ms(uint32_t xms)
{
	while(xms--)
	{
		Delay_us(1000);
	}
}
void Delay_s(uint32_t xs)
{
	while(xs--)
	{
		Delay_ms(1000);
	}
}
c 复制代码
/*第二种写法:需要进行延时的初始化,在初始化的时候配置滴答定时器
过多长时间进行一次中断(通常为1ms),此后不在配置。定义一个系统时间,
在定时器中断里进行加一。需要进行延时处理的时候,在延时函数里定义一
个新的变量,并将系统时间和需要延时的时间相加赋给这个变量,然后等待
系统时间等于这个变量。
*/

vu32 System_Time = 0;//系统时间
void SysTick_Handler(void)
{
	System_Time++;//1ms自加一次
}

void delay_ms(uint32_t time)
{
	uint32_t tick = System_Time + time;
	while(System_Time < tick)  //等待系统时间等于tick
	{}
}

//系统定时器的初始化
//想要1ms来一次中断
//参数:重装载值
void SysTick_Init(uint32_t reload)
{
	if(SysTick_Config(reload))
	{
		while(1);
	}
}
void delay_us(uint32_t time)
{
	while(time--)
		delay_1us();
}

while(1)
{
//延时初始化 1ms
	SysTick_Init(72000); 
}
/*
由于这个延时时间是以ms为单位的,需要us延时时可以加入汇编中
的------NOP()命令进行空等待。
*/
#define delay_1us()	{\
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();\
}
/*延迟初始化函数,实际是调用了SysTick_Config()函数,
这个函数为标准库中函数库 */
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{ 
//判断自动重装值是否超过界限。
  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            
//设置自动重装值                                                            
  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;     
//设置滴答定时器中断
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  
//将VAL清零
  SysTick->VAL   = 0;                                        
//配置CTRL 1分频,打开中断,开滴答定时器
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | 
                   SysTick_CTRL_TICKINT_Msk   | 
                   SysTick_CTRL_ENABLE_Msk;                    
  return (0);                                                  
}

5.串口printf

printf函数输出流程:

我们通过需要输出的硬件来重新定义fputc()函数.

c 复制代码
/*
	重定义fputc函数,使printf()函数在打印的过程中,
	也将数据通过串口进行输出
*/
int fputc(int ch, FILE *f)
{
	Serial_SendByte(ch);			//将printf的底层重定向到自己的发送字节函数
	return ch;
}

//	其他串口使用printf()
/*
	方法一: 定义一个数组,使用sprintf()函数进行中转一下
		   再用该串口发送字符串的函数进行发送。
*/
char string[100];
sprintf(string,"num=%d\r\n",555);
serial_sendstring(string);

/*
  方法二:封装sprintf()
*/
void Serial_Printf(char *format, ...)
{
	char String[100];				//定义字符数组
	va_list arg;					//定义可变参数列表数据类型的变量arg
	va_start(arg, format);			//从format开始,接收参数列表到arg变量
	vsprintf(String, format, arg);	//使用vsprintf打印格式化字符串和参数列表到字符数组中
	va_end(arg);					//结束变量arg
	Serial_SendString(String);		//其他串口发送字符数组(字符串)
}

6.独立看门狗

IWDG:独立看门狗

本质:可以产生系统复位信号的计数器。

特点:时钟为低速时钟LSI(40kHZ)由独立的RC振荡器提供(可在停止和待机模式下运行)

看门狗被激活后,当递减计数器计数到0x000时,产生系统复位。

喂狗:在计数器计数到0之前要进行喂狗,防止系统一直被复位。

c 复制代码
	/*IWDG初始化*/
	//独立看门狗的时钟为40khz 低速时钟LSI驱动
void IWDG_init()	
{	
	//独立看门狗写使能
	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);	
	//设置预分频为16
	IWDG_SetPrescaler(IWDG_Prescaler_16);
	/设置重装值为2499,独立看门狗的超时时间为1000ms 范围0~4095			
	IWDG_SetReload(2499);	
	//重装计数器,喂狗						
	IWDG_ReloadCounter();			
	//独立看门狗使能				
	IWDG_Enable();									
}

7.不定时跟新...

相关推荐
TeYiToKu8 分钟前
笔记整理—内核!启动!—linux应用编程、网络编程部分(6)随机数与proc文件系统
linux·c语言·arm开发·笔记·嵌入式硬件
PegasusYu36 分钟前
STM32CUBEIDE FreeRTOS操作教程(五):mutex互斥信号量
stm32·mutex·rtos·信号量·stm32cubeide·free-rtos·互斥信号量
会编程的果子君2 小时前
51单片机系列-按键检测原理
单片机·嵌入式硬件·51单片机
weixin_586062022 小时前
单片机原理与应用
单片机·嵌入式硬件
未来之窗软件服务2 小时前
酒店智能门锁接口pro[V10] 对接酒店收银-SAAS本地化-未来之窗行业应用跨平台架构
stm32·单片机·嵌入式硬件·酒店管理系统·酒店门锁
夜间去看海3 小时前
基于单片机的智能窗帘控制系统
单片机·嵌入式硬件
哦豁灬7 小时前
树莓派pico上手
单片机·嵌入式硬件·micropython·树莓派pico
boldht9 小时前
嵌入式项目:STM32平衡车详解 (基础知识篇) (基于STM32F103C8T6)
c语言·stm32·单片机·嵌入式硬件·嵌入式项目·单片机平衡小车
夜间去看海9 小时前
基于单片机的角度、水位、温度、辅助热源、电机仿真
单片机·嵌入式硬件
夜间去看海10 小时前
基于单片机的小车行走加温湿度检测系统
单片机·嵌入式硬件·proteus