stm32学习笔记

本文详细介绍了STM32的中断配置原理及应用,包括抢占与响应优先级的概念,并深入探讨了USART串口通信配置过程。此外,还涉及了GPIO、定时器输入捕获、SRAM与DRAM等概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

中断配置


  • 抢占优先级高的可以打断抢占优先级低的,但如果抢占优先级都一样,如果没同时发生,响应优先级高的不能打断低的,但如果同时发生,响应优先级高的先执行。
  • 中断原理:程序进行中遇见了中断请求,执行中断服务函数,服务函数执行完后继续执行程序。
  • 四位寄存器进行分组-**若分组为2,两位为抢占优先级,两位为响应优先级,所以抢占优先级和响应优先级可以是0123,因为2为二进制表示数有11 10 01 00

这么多中断需要通过NVIC(内嵌向量中断控制器)来管理。

设置中断总共分三步:

1.设置中断优先级分组。

//类似于划分“阶级成分”

2.设置某中断的中断优先级

//类似于判定具体的“阶级成分”

3.使能NVIC中的该中断

//类似于“宣布判决”

以下内容摘自 https://www.cnblogs.com/121792730applllo/p/5155368.html

形象化的理解是:

你是上帝,造了N个人,这么多人要分社会阶级和社会阶层了。由于“阶级”的词性比较重,"阶层"比较中性,所以preemption优先级->阶级;每个阶级内部,有一些阶层,sub优先级->阶层。

如果按照NVIC_PriorityGroup_4这么分,就分为了16个阶级(1个阶层就是1个preemption优先级),0个阶层;高阶级的人,可以打断低阶级的正在做事的人(嵌套),最多可以完成1个中断和15级嵌套。每个阶级(每个preemption优先级),你来指定这43人中,谁进入该阶级;一个人叫EXTI0_IRQChannel,你指定他进入“阶级8”,则
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 8; // 指定抢占式优先级别1,可取0-15

另外,在同一阶级内部,一个人在做事的时候,另外一个人不能打断他;(preemption优先级别相同的中断源之间没有嵌套关系)还有,如果他们两个同时想做事,因为没有阶层,那么就根据Vector table中的物理排序,让排名靠前的人去做;又有1个人SPI1_IRQChannel,设定如下
NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 指定抢占式优先级别1,可取0-15

SPI1_IRQChannel的阶级高,EXTI0_IRQChannel做事的时候可以打断(嵌套)。

如果按照NVIC_PriorityGroup_3这么分,就分为了8个阶级(1个阶级是1个preemption优先级),每个阶级内有2个阶层(sub优先级);高阶级的人,可以打断低阶级的正在做事的人(嵌套),最多可以完成1个中断和7级嵌套。每个阶级(每个preemption优先级),你来指定这43人中,谁进入该阶级;一个人叫EXTI0_IRQChannel,你指定他进入“阶级3”,则:
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 指定抢占式优先级别1,可取0-7
还需要指定他的阶层:
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 指定响应优先级别0,可取0-1

另有1个人叫EXTI9_5_IRQChannel,他的阶级和阶层设定如下
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 指定抢占式优先级别0,可取0-7
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 指定响应优先级别1

那么这两个人是同一阶级的兄弟,一个人在做事的时候,另外一个人不能打断他;(preemption优先级别相同的中断源之间没有嵌套关系)
如果他们两个同时想做事,因为前者的阶层高,所以前者优先。

————————————————
版权声明:本文为CSDN博主「野猪力量」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wofreeo/article/details/82346588

还有一个人叫USART1_IRQChannel,他的阶级和阶层设定如下
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // 指定抢占式优先级别0,可取0-7
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 指定响应优先级别1

USART1_IRQChannel的优先级最高,当前面两个人做事的时候,他都可以打断(嵌套)。

以下的类推。
————————————————
版权声明:本文为CSDN博主「野猪力量」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wofreeo/article/details/82346588

ustart配置

1.概念
在STM32的参考手册中,串口被描述成通用同步异步收发器(USART),它提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换。(好吧我也不是很懂,暂且贴上官方定义,各位看官自己悟吧)
配置步骤

2.打开时钟(RCC配置)
由于UART的TX和RX和AFIO都挂在APB2桥上,因此采用固件库函数RCC_APB2PeriphClockCmd()进行初始化。UARTx需要分情况讨论,如果是UART1,则挂在APB2桥上,因此采用RCC_APB2PeriphClockCmd()进行初始化,其余的UART2~5均挂在APB1上。

3.GPIO配置
GPIO的属性包含在结构体GPIO_InitTypeDef,其中对于TX引脚,GPIO_Mode字段设置为GPIO_Mode_AF_PP(复用推挽输出),GPIO_Speed切换速率设置为GPIO_Speed_50MHz;对于RX引脚,GPIO_Mode字段设置为GPIO_Mode_IN_FLOATING(浮空输入),不需要设置切换速率。最后通过GPIO_Init()使能IO口。

4.NVIC配置
STM32在只有一个中断的情况下,仍然需要配置优先级,其作用是使能某条中断的触发通道。STM32的中断有至多两个层次,分别是抢占优先级(主优先级)和子优先级(从优先级),而整个优先级设置参数的长度为4位,因此需要首先划分抢占优先级位数和子优先级位数,通过NVIC_PriorityGroupConfig()实现;

5.特定设备的中断优先级NVIC的属性包含在结构体NVIC_InitTypeDef中,其中字段NVIC_IRQChannel包含了设备的中断向量,保存在启动代码中;字段NVIC_IRQChannelPreemptionPriority为主优先级NVIC_IRQChannelSubPriority为从优先级,取值的范围应根据位数划分的情况而定;最后NVIC_IRQChannelCmd字段是是否使能,一般置为ENABLE。最后通过NVIC_Init()来使能这一中断向量。

USART配置
通过结构体USART_InitTypeDef来确定。UART模式下的字段如下:

USART_BaudRate:波特率(每秒能传输的数据位),缺省值为9600。

USART_WordLength:字长

USART_StopBits:停止位

USART_Parity:校验方式(奇偶校验)

USART_HardwareFlowControl:硬件流控制

USART_Mode:单/双工,即收发状态。

最后通过USART_Init()来设置。

代码汇总
————————————————
版权声明:本文为CSDN博主「Andrew_Ren」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/XJTU_Richthofen/article/details/50719618


void uart_init(u32 bound){

    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1和GPIOA时钟
    USART_DeInit(USART1);  //复位串口1(各参数置为缺省值)

    //USART1_TX(发送数据)   PA.9引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA.9

    //USART1_RX(接收数据)     PA.10引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PA.10

   //NVIC中断向量配置 
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级置为3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;      //子优先级置为3,优先级依据不同的中断重要性不同来确定。
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure); //根据上面设置的参数初始化NVIC寄存器

   //USART初始化设置
    USART_InitStructure.USART_BaudRate = bound;//波特率为9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//1个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式

    USART_Init(USART1, &USART_InitStructure); //串口初始化
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//中断开启
    USART_Cmd(USART1, ENABLE);             //串口使能

}
————————————————
版权声明:本文为CSDN博主「Andrew_Ren」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接<https://blog.csdn.net/XJTU_Richthofen/article/details/50719618>

  • 通信方式分为串行通信并行通信


    串行:就是数据按位顺序进行传输 并行:就是数据各个位同时传输

    一般我们都用串行通信

    • 串行通信分为同步通信异步通信

      同步通信:就是根据时钟信号进行传输,比如当时钟信号处于上升沿的时候,发送一个比特数据。数据发送都是根据时钟信号来的。

      异步通信:没有时钟线但是通信的两端事先约定好了波特率bound(其实就是约定好一起干什么),比方我1s从一个设备发送一个数据,另一个设备就约定好1s后接受一个数据.就是把数据发送和接受的时间都约定好。

  • 全双工和半双工

    USART:universal synchronous asynchronous receiver and transmitter通用同步异步收发器
    UART:universal asynchronous receiver and transmitter通用异步收发器

    USART支持同步模式,因此USART 需要同步始终信号USART_CK(如STM32 单片机)
    当进行异步通信时,这两者是没有区别的。区别在于USART比UART多了同步通信功能。
    这个同步通信功能可以把USART当做SPI来用,比如用USART来驱动SPI设备

    同步是指:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。
    异步是指:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。

    同步是阻塞模式,异步是非阻塞模式。

    USART支持同步模式,因此USART 需要同步始终信号USART_CK(如STM32 单片机),通常情况同步信号很少使用,因此一般的单片机UART和USART使用方式是一样的,都使用异步模式。

    其中SPI IIC为同步通信 UART为异步通信, usart为同步&异步通信。

    单工、半双工、全双工
    单工数据传输只支持数据在一个方向上传输;
    半双工数据传输允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;
    全双工数据通信允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。

    I2C是半双工,SPI的全双工,uart是全双工。

    串口助手实验现象:中断服务函数如下所示

    void USART2_IRQHandler(void) //串口2中断服务程序 { u8 res; if(USART_GetITStatus(USART2,USART_IT_RXNE)!=RESET) { res= USART_ReceiveData(USART2); USART_SendData(USART2,res); } LED0=!LED0;

    现象,发送的数据在串口助手上显示出来,发送a,就显示a(就一个a,没其他现象)

gpio工作模式

位操作
  • 用位操作的时候,先要设置引脚模式。配置成输入模式才可以使用p(n)in,配置成输出才可以使用p(n)out;

    APB1:通常为36MHz,APB2通常为72MHz也有48MHz

时钟配置
  • 时钟配置由系统初始化函数system_stm32f10x.c配置,一般正点原子已经给你配好了,72MhzHSE外部时钟提供。
  • gpio复用功能

大多数io口不能复用,有些io口可以复用,复用的意思就是既可以当作普通io口来进行使用也可以当作其他外设接口来使用,比如PA9与PA10,可以当作usart1_rx和usart1_tx作为串口1接口,PB6,PB7

可以作为SCL,SDA I^2C通信传输接口。

gpio初始化函数
  • GPIO_Init(),这个函数的功能是帮助编程者设置相应gpio口的寄存器值。
gpio开漏和推挽输出区别
  • 开漏输出GPIO_OUT_OD 高电平是通过外部上拉决定,低电平通过nmos管使能状态决定,其中cpu写入逻辑1时,nmos管关闭,输出电平由外部上拉决定,cpu写入0时,nmos管打开拉低电平,输出低电平。
  • 推挽输出GPIO_OUT_PP。输出电平由内部决定,cpu写入1pmos管打开,VDD上拉输出高电平,cpu写入0,VSS nmos管下拉输出低电平。
    GPIO引脚模式

快捷键

  • crtl+F打开keil搜索框

位进制知识

  • 1个bit(比特)对应二进制的一个数,8bit对应1111 1111.

  • 计算机:用数的十六进制表示地址0110 0101-地址(35H)-真值(53)

  • 一个地址等于一个字节,所以一个地址占8位,如果存储32位的数据,需要四个地址存储。

  • 8位数据表示范围
    0111 1111表示最大值26+25+…+21+20=127,0是符号位。
    1111 1111表示最小值,同上计算为-127
    范围为[-127,+127]

  • 8位二进制原码表示的范围,即
    0111111111111111,即-127+127
    但若是补码就不是这个范围了,应该是-128~+127

  • 8位二进制原码的表示范围:-127~+127
    8位二进制反码的表示范围:-127~+127
    8位二进制补码的表示范围:-128~+127

  • 发送的字符串转换为二进制原理。
    比方:小写字母a对应ASCLL码的是97,97对应的二进制就是11 00001,为7位二进制。如果串口要发送字母a,传输的数据长度必须大于等于7

  • 8位和位8意思不一样。

    8位:代表位0~7;

    位8: 位0~8的二进制9位中的位8;

按键输入

//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//0,没有任何按键按下
//1,KEY0按下
//2,KEY1按下
//3,KEY2按下 
//4,KEY3按下 WK_UP
//注意此函数有响应优先级,KEY0>KEY1>KEY2>KEY3!!
u8 KEY_Scan(u8 mode)
{	 
	static u8 key_up=1;//按键按松开标志
	if(mode)key_up=1;  //支持连按		  
	if(key_up&&(KEY0==0||KEY1==0||KEY2==0||WK_UP==1))
	{
		delay_ms(10);//去抖动 
		key_up=0;
		if(KEY0==0)return KEY0_PRES;
		else if(KEY1==0)return KEY1_PRES;
		else if(KEY2==0)return KEY2_PRES;
		else if(WK_UP==1)return WKUP_PRES;
	}else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0)key_up=1; 	    
 	return 0;// 无按键按下
}

/*记忆说明笔记
连按模式:只要是低电平就是有效执行电平,这按下的所有低电平都有效,比如按键检测频率为100ms,你按了1s,就会执行10次对应的工作。
不能连按模式:如果按了一次,就只能执行一次,就只有第一次的低电平有效,其他的无效,如果想执行第二次,只能松下在按。
只有,前一次为松开时,下一次按下的电平才有效。比如上面的程序所示,key_up=1表示为松开状态,使用static变量,每次key_up的值与返回值相同,如果key0=0,此时按下,key_up置为0表示没有松开,下次执行的时候,if(key_up&&(KEY0==0||KEY1==0||KEY2==0||WK_UP==1))为假,key0=0,else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0)key_up=1; 
为假,返回0,即没有工作执行。如果松开,key_up重新置为1。继续进行下一次按键扫描,原理同上。
 */  

独立看门狗和窗口看门狗

独立看门狗:就是为了防止单片机程序出现意外停止跑飞或者出现死循环,可当作检测系统。

原理:计数寄存器,使能计数寄存器后,计数寄存器会重0xfff开始往下计数,然后计数到零会使能程序复位,重新开始。如果往KR寄存器写入0xccccc,rlr自动重装寄存器数据会写入计数寄存器中,计数器开始重自动重装载值开始往下计数,然后可以不停的写入自动重装载值,计数寄存器就会不停的重自动重装载值重新计数,就不会出现计数到零的情况,程序就不会复位。

/ / 时 间 计 算 ( 大 概 ) : T o u t = ( ( 4 ∗ 2 p r e r ) ∗ r l r ) / 40 ( m s ) . //时间计算(大概):Tout=((4*2^prer)*rlr)/40 (ms). //():Tout=((42prer)rlr)/40(ms).
溢出时间就是计数器计数周期,比方说计数器的周期为1s,那么重自动重装载值计数到0的时间为1s。所以为了程序一直执行,喂狗间隙必须控制在1s以内,不然间隙超过了1s,程序计数已经经过1s计到0,就发生了复位信号。

窗口看门狗:就是独立看门狗的升级版,因为如果出现以下程序错误现象:

  • 程序跑乱了但是在独立看门狗的溢出时间内又恢复成正常运行状态,所以这段时间是可以进行喂狗操作的(喂狗间隙在溢出时间以内,比方说1s,只要控制在1s内喂狗,程序都可以继续执行)如果程序跑飞了0.25s,只有这0.25s不能进行喂狗操作,但是剩下的0.75s依然可以进行喂狗,程序依然不会复位,所以即使程序跑乱了,也不会产生复位操作,所以就达不到程序出错就复位的情况。
  • 程序出错了并且出错的地方刚好执行了刷新看门狗的操作,所以现在程序出错了,但是依然不会进行复位操作。这不是我们想要的

独立看门狗就不能很好的实现看门狗的功能。

现在就启用***窗口看门狗***来更精确的进行,解决以上程序出错问题。窗口看门狗在于他的周期时间是一个精确区间,如果程序想不被复位的话,喂狗时间就需要精准把握。所以程序一旦出错,不管是什么错,都很难执行喂狗刷新操作,程序就会进行复位操作。

窗口看门狗原理:如果在计数寄存器计数值大于窗口上限值(可以设定)喂狗,程序就会产生复位操作。计数寄存器的值小于窗口上限值且大于0x40(1000000),这段时间进行喂狗操作,程序就不会产生复位操作。计数寄存器的值有0x40(1000000)变为0x3f(0111111)【0x40=0x3f+1 0x40其实就是0x3f的前一位】时,程序也会进行复位操作。
在这里插入图片描述

其中 T[5:0]+1表示窗口寄存器的值就是计数器的初值,计数时间为最大值,就是从初值(窗口寄存器设定值)计数到0x40的时间+1。

时间计算
在这里插入图片描述

0x52-0x3f就转化为十进制来计算。

注意:反正那个T[5:0]+1就是计数器从初值减去0x3f或者就是减去0x40+1;一样的道理,不必追究!

定时器


定时器框图在这里插入图片描述

输入捕获和pwm输出都属于定时器内部功能,所以配置的时候只需要使能定时器就行,有中断就使能中断

输入捕获实验

  • 输入捕获滤波的原理:**就是上升沿开始捕获,每次上升沿触发捕获8次高电平,如果每次是高电平,则表示有效触发,触发一次中断。
  • 在这里插入图片描述

无用脉冲需要滤掉!如果没有设置捕获几次(没有滤波操作),那么波动的无用脉冲就会被一起捕获进去

重点重点!


u8  TIM5CH1_CAPTURE_STA=0;	//输入捕获状态		    				
u16	TIM5CH1_CAPTURE_VAL;	//输入捕获值
 
//定时器5中断服务程序	 
void TIM5_IRQHandler(void)
{ 

 	if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获[如果捕获成功就不执行中断程序了]	
	{	  
		if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)//[是否发生溢出中断。如果发生溢出中断,则表示捕获电平脉冲有一点长,超过了定时器的计数周期。如果没有发生溢出中断,则表示捕获脉冲宽度比较短,在定时器计数的计数周期内。]
		 
		{	    
			if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平了
			{
				if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了[长到超过了STA的计数次数最大值,开始强制解除捕获输入]
				{
					TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次
					TIM5CH1_CAPTURE_VAL=0XFFFF;
				}else TIM5CH1_CAPTURE_STA++;
			}	 
		}
	if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//捕获1发生捕获事件[触发了捕获中断,表明捕获了一次上升或下降沿]
		{	
			if(TIM5CH1_CAPTURE_STA&0X40)		//捕获到一个下降沿[这里STA初值为0,所以执行else后的语句] 		
			{	  			
				TIM5CH1_CAPTURE_STA|=0X80;		//标记成功捕获到一次高电平脉宽
				TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
		   		TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获
			}else  								//还未开始,第一次捕获上升沿[这里开始看程序运作]
			{
				TIM5CH1_CAPTURE_STA=0;			//清空
				TIM5CH1_CAPTURE_VAL=0;
	 			TIM_SetCounter(TIM5,0);
				TIM5CH1_CAPTURE_STA|=0X40;		//标记捕获到了上升沿[STA的第位6设置为1,表示捕获到了高电平]
		   		TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);		//CC1P=1 设置为下降沿捕获[为下一次捕获下降沿做准备]
			}		    
		}			     	    					   
 	}
 
    TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位
 
}

注:

  • STA这个变量是自己设置的,作用类似寄存器。位7置为1表示捕获完成,位6置为1,表示捕获到了高电平,位0-5用来计算溢出中断次数。数都是自己根据程序设置的。

  • if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿
    {
    temp=TIM5CH1_CAPTURE_STA&0X3F;
    temp*=65536;//溢出时间总和
    temp+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间
    printf(“HIGH:%d us\r\n”,temp);//打印总的高点平时间
    TIM5CH1_CAPTURE_STA=0;//开启下一次捕获

    下一次中段开启之前,STA先清零!

  • 设置捕获状态就是什么时候开始捕获

  • 如果定时器以1Mhz进行计数,那么计一个数就需要1us,设置Arr位最大值,即有65536个数,需要65536us!
    在这里插入图片描述

  • pwm模式与有效无效电平

    pwm模式1计数值cnt<ccr1时输出有效电平,>则输出无效电平
    pwm模式2计数值cnt<ccr1时输出无效电平,>则输出有效电平
    高电平/低电平有效模式1低电平有效:cnt<ccr1输出有效低电平,cnt>ccr1输出无效电平(为高电平) 模式2高电平有效:cnt<ccr1输出无效电平(低电平),cnt>ccr1输出有效高电平

SRAM-DRAM-ROM-RAM

  • RAM:随机存取存储器,全称:Random access memory*,是与cpu直接交换数据的内部存储器。断电后,数据会立马消失

    SRAN静态随机存储器,数据只要写入,不断电数据就不会消失,断电后也会消失,这是它跟ROM的区别。同时读出数据不会破坏原来存放的信息,一次写入可以多次读出。
    DRAM动态随机存储器,数据写入,要保持数据的话必须随时刷新电路(实际数字电路就是不断给带带电容充电),断电后数据也会消失。
  • ROM:只读存储器,全称:Read only Memory,数据只要写进去了,断电后不会消失。类似手机内存(256G),本义是只可以读,不可以写,但现在大都认为可以写。

i2c通信

  • 应答信号
    主机(单片机)向从机(比如oled,eeprom)写数据,写完数据后,SDA释放总线(由主设备释放),SDA线改为由从设备控制,如果SDA拉低,就产生ACK应答信号,如果被拉高,就产生非应答信号。

  • 如果是主设备(单片机)接受从设备传来的数据,也就是从设备为发送器,在从设备发送完数据后,从设备释放总线,然后SDA交给单片机控制,单片机可以产生应答信号和非应答信号,在接收完数据之后。

    //测试程序
    #include<iostream.h>
    void main()
    {
    	int a[8]={1,0,1,1,0,1,0,1};
    int i=0;
    int READ=0;
    for(i=0;i<8;i++)
    {
    	READ<<=1;
    if(a[i])READ++;
    }
    cout<<hex<<READ;
    
    }
    //接收数据也是从高位开始的
    
    
    
    //正带原子接收数据程序
    u8 IIC_Read_Byte(unsigned char ack)
    {
    	unsigned char i,receive=0;
    	SDA_IN();//SDA设置为输入
        for(i=0;i<8;i++ )
    	{
            IIC_SCL=0; 
            delay_us(2);
    		IIC_SCL=1;
            receive<<=1;
            if(READ_SDA)receive++;   
    		delay_us(1); 
        }					 
        if (!ack)
            IIC_NAck();//发送nACK
        else
            IIC_Ack(); //发送ACK   
        return receive;
    }
    
### STM32学习资源推荐 对于希望深入学习STM32微控制器的开发者来说,获取高质量的学习资料至关重要。以下是几个方向可以帮助找到适合的学习材料: #### 官方文档 STMicroelectronics 提供了详尽的技术手册和数据表,这些官方文档涵盖了从基础到高级的各种主题[^1]。通过访问 ST 的官方网站,可以下载最新的芯片规格书、应用笔记以及固件库。 #### 社区分享与博客文章 网络上存在大量由经验丰富的工程师撰写的STM32学习笔记,例如提到的“Stm32学习笔记,3万字超详细”的内容就非常有价值。这类笔记通常会结合实际项目经历来解释复杂的概念,并提供实用的操作指南。此外,“【笔记】STM32篇”这样的记录也强调了实践的重要性——鼓励读者亲自尝试编码过程以加深理解[^2]。 #### 开发环境搭建指导 为了顺利开展基于STM32项目的开发工作,熟悉如何配置IDE(如Keil MDK或者STM32CubeIDE),安装必要的驱动程序也是必不可少的一环。许多在线教程都会详细介绍这一流程并附带截图说明以便于新手快速上手。 #### 中断处理函数解析 针对具体功能模块比如外部中断线(EXTI),需要注意不同版本API间可能存在的细微差异。虽然有说法指出`EXTI_ClearFlag` 和 `EXTI_ClearITPendingBit` 在某些实现里表现一致但实际上它们各自承担着不同的职责,在特定场景下选用合适的清除方法能够提高系统的稳定性和效率。 ```c // 示例代码展示如何正确使用上述两个宏定义 void EXTI0_IRQHandler(void){ if(__HAL_GPIO_EXTI_GET_FLAG(GPIO_PIN_0)!=RESET){ __HAL_GPIO_EXTI_CLEAR_FLAG(GPIO_PIN_0); // 使用此方式清标志位更直观些 /* Add your application code here */ } } ``` #### PDF资源整合建议 如果偏好纸质阅读体验,则可以通过搜索引擎查找关键词组合:“stm32 学习 教程 pdf”,这样往往能找到一些整理成册的手册文件可供离线查看。不过要注意甄别来源可靠性以免误信过期信息。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁芜~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值