STM32
直播中

贾飞小

7年用户 1757经验值
私信 关注
[问答]

如何在输出模式下准确得到IO外部的电平信号

如何在输出模式下准确得到IO外部的电平信号?
Dcode总线与DMA总线有哪些不同?

回帖(1)

刘耀清

2021-11-10 09:12:55
  #启动文件与容量的对应关系:
  #GPIO端口:
  #IO口输入保护二极管电路:
  当输入的电压超过VDD时,上面的二极管导通,I/O引脚则被钳位成VDD;而当输入的电压低于VSS时,下面的二极管导通,I/O引脚则被钳位成VSS.。。
  总之使得输入电源始终位于VDD到VSS之间。
  GPIO操作相关寄存器:
  1, GPIOx_CRL 配置寄存器 32bit
  2, GPIOx_CRH 配置寄存器 32bit
  3, GPIOx_IDR 数据寄存器 32bit
  4, GPIOx_ODR 数据寄存器 32Bit(输出寄存器只能对寄存器进行整体操作)
  5, GPIOx_BSRR 置位复位寄存器 32bit(可以对各个ODR位进行独立的设置/清除操作)
  6, GPIOx_BRR 复位寄存器 16bit
  7, GPIOx_LCKP 锁定寄存器 32bit
  所有GPIO口都有内部弱上拉和弱下拉,但配置为输入时,它们可以被激活,也可以被断开。
  IO的输入配置:
  IO口的输出配置:
  重点:
  #当IO口被配置为输出模式时:
  1, 出现在IO脚上的数据在每个APB2时钟被采样到输入数据寄存器
  2, 在开漏模式时,对输入数据寄存器的访问可得到IO口的状态
  #复用输出配置:
  #如何在输出模式下准确得到IO外部的电平信号:
  只有在开漏输出/复用开漏输出的时候,当输出1时,NMOS管关闭,此时IO信号完全由外部信号决定,这是读取的就是IO的输入信号。其他时候读取的输入信号都是不准确的,是受到输出影响的。(推挽输出/复用推挽输出)
  #当IO口开漏输出时:不能够使用5V的上拉电阻将IO上拉至5V,因为IO口有保护二极管电路,会将点位钳位至Vdd+二极管压降、Vss-二极管压降。
  时钟系统:
  1, HIS RC:内置高速RC振荡器, 8M, 不精确, 一般不用;
  2, LSI RC: 内部低速RC振荡器 40k 不精确
  3, HSE Osc: 外部高速晶振 4~16M
  4, LSE Osc : 外部低速晶振, 32.768k
  5, PLL:锁相环, 将输入频率倍频至72M为PLLCLK,供SYSCLK选择。
  #核心时钟模块:
  SYSCLK: 系统时钟(来源:HIS,PLL,HSE,HSE)《css:监视器,一旦HSE失效,即改时钟为HSI》
  #SYSCLK系统时钟分配:
  1, AHB预分频器:可以对SYSCLK时钟进行分频
  2, APB1 预分频器:
  3,APB2 预分频器:
  4,USB 预分频器:
  #STM32系统架构:
  ARM体系结构:Advanced RISCMachines
  #驱动单元:
  Icode总线:
  我们写好的程序写好后通过编译都变成一条条指令存储在外设的FLASH里面,内核要读取这些指令来执行程序就必须通过Icode总线(专门用来取指)。
  Dcode总线与DMA总线:
  即为DATA,我们知道常量const存放在内部FLASH里面,而变量存在内部SRAM里面。这些数据可以由DCode和DMA来读取,为了避免两者同时去读取数据从而造成冲突,所以在两者读取数据的时候会有一个总线矩阵来裁定谁来读取数据。
  System总线:
  读取数据,最主要还是用来访问外设的寄存器,即读写寄存器都是通过这条总线来完成的。
  DMA总线:
  说先说这条总线也是主要传输数据的,这个数据可以是某个外设的数据寄存器,可以是SRAM,可以是内部的FLASH 。
  #被动单元
  FLASH:
  程序存储器
  SRAM:
  静态存储器
  FSMC:
  外部RAM总线
  AHP:
  高速总线
  #STM32储存映像
  #启动文件的作用:
  设置堆栈指针、设置PC指针、初始化中断向量表、配置系统时钟、调用C程序的main()函数执行C代码。
  #STM32固件库:
  #内核之外的寄存器的映射:
  Stm32f10x.h: 实现了内核之外的外设的寄存器映射
  #时钟配置文件:
  System_stm32f10x.c:上电后初始化时钟、拓展外部存储器
  #外设驱动:
  Stm32f10x_xx.c: 外设驱动的库函数文件
  Stm32f10x_xx.h: 存放外设初始化结构体和初始化结构体成员的参数列表,外设固件库函数的声明
  #内核外设:
  Core_cm3.h: 实现了内核里面的寄存器的映射
  Core_cm3.c: 实现了一些操作内核外设的函数(用的比较少)
  #Misc.h: NCIV(嵌套向量中断控制器)、systic(系统滴答定时器)
  Misc.c:这个文件提供了外设对内核中NVIC(中断向量控制器)的访问函数,用于配置中断。
  #头文件配置文件:
  Stm32f10x_conf.h: 所有外设的头文件都包含在其中
  #专门存放中断服务函数的文件:
  Stm32f10x_it.c
  Stm32f10x_it.h
  //中断服务函数可以随便放在其他任何地方。
  #stm32位带操作
  STM32位带区的一个位在位带别名区膨胀为4个字节,两个位带别名区分别是SRAM的最低1M、片内外设的最低1M,所有的片内外设寄存器地址映射均在片内外设地址的最低1M空间内,所以可以对所有的寄存器进行“位寻址”操作。
  #由位带区想要操作寄存器的n位及其寄存器地址addr,可以通过统一的公式找到别名去对应的4个字节的起始地址:
  ADDR=((addr&0xf0000000)+0x02000000+((addr&0x00ffffff)《《5)+(n《《2))
  #库函数编程学习:
  #启动文件选择:
  #RCC
  RCC是STM32的时钟控制器,可开启或关闭各总线的时钟,在使用各外设功能必须先开启其对应的时钟,没有这个时钟内部的各器件就不能运行。
  #RCC寄存器
  1, RCC_CR: 时钟控制寄存器:各个时钟的使能、准备就绪等
  2,RCC_CFGR:时钟配置寄存器:各个预分频器的输入时钟选择、各个预分频器的分频因子
  3,RCC_CIR :时钟中断寄存器:中断使能
  4,RCC_APB2RSTR:APB2外设复位寄存器
  5,RCC_APB1RSTR:APB1外设复位寄存器
  6,RCC_AHBENR:AHB外设时钟使能寄存器
  7,RCC_APB2ENR:APB2时钟使能
  8,APB1 外设时钟使能寄存器(RCC_APB1ENR)
  9,备份域控制寄存器(RCC_BDCR)
  10,控制/状态寄存器(RCC_CSR)
  11,AHB外设时钟复位寄存器(RCC_AHBRSTR)
  12,时钟配置寄存器2(RCC_CFGR2)
  #stm32f10x.h:
  1,定义结构体类型,用定义的类型将下面定义的各外设的基址指针化供之后操作。
  1, 给各外设地址取宏名
  2, 将宏名代表的地址用结构体指针化
  #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
  #操作寄存器的方法:
  GPIOA-》CRL = 0x00000000 çè((GPIO_TypeDef *) GPIOA_BASE) = 0x00000000
  3, Bit definition for XXX register,使用宏来替换各个寄存器中的值来配置各个寄存器,使用宏名便于观察理解,不易出错。(宏数据的位数取决于寄存器的位数)
  #Systic:系统定时器(寄存器)
  1, CTRL : SysTick寄存器
  2, LOAD : Systic重装载值寄存器
  3, VAL : SysTic 当前值寄存器
  4, CALIB : Systic校准值寄存器
  #由于Systick是挂载在内核上的,所以只要内核有时钟,直接配置Systick相关的寄存器就可以开始工作了;
  #与Systick相关的函数有两个: 库里SysTick相关的函数我们能找到两个
  一个在msic.h中
  voidSysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
  {
  /* Check the parameters */
  assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));
  if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
  {
  SysTick-》CTRL |= SysTick_CLKSource_HCLK;
  }
  else
  {
  SysTick-》CTRL &= SysTick_CLKSource_HCLK_Div8;
  }
  }
  一个在core_m3.h中
  static__INLINE uint32_t SysTick_Config(uint32_t ticks)
  {
  if (ticks 》SysTick_LOAD_RELOAD_Msk) return(1); /* Reload value impossible */
  SysTick-》LOAD =(ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* setreload register */
  NVIC_SetPriority(SysTick_IRQn, (1《《__NVIC_PRIO_BITS) - 1);
  /*set Priority for Cortex-M0 System Interrupts */
  SysTick-》VAL =0; /*Load the SysTick Counter Value */
  SysTick-》CTRL =SysTick_CTRL_CLKSOURCE_Msk |
  SysTick_CTRL_TICKINT_Msk |
  SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
  return(0); /* Function successful */
  }
  我们一般只需要后一个就可以了
  需要的操作在SysTick_Handler()中添加就好了,意思每到加载到SysTick中的值减到0时就执行SysTick();
  在 SysTick_Config()库函数还调用了固件库函数 NVIC_SetPriority()来配置系统定时器的中断优先级,该库函数也在 core_m3.h 中定义,原型如下:
  __STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
  2 {
  3 if ((int32_t)IRQn 《 0) {
  4 SCB-》SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] =
  5 (uint8_t)((priority 《《 (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
  6 } else {
  7 NVIC-》IP[((uint32_t)(int32_t)IRQn)] =
  8 (uint8_t)((priority 《《 (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
  9 }
  10 }
  #启动文件简介
  启动文件由汇编编写,是系统上电复位后第一个执行的程序。主要做了以下工作:
  1, 初始化堆栈指针SP=_initial_ap
  2, 初始化PC指针=Reset_Handler
  3, 初始化中断向量表
  4, 配置系统时钟
  5, 调用C库函数_main()初始化用户堆栈,从而最终调用 main 函数去到 C 的世界;
  #STM32中断(中断即异常)
  #CM3内核支持256个中断,其中有16个内核中断和240个外部中断,并且具有256级的可编程中断设置;
  Stm32并没有使用到,有16个内核中断和86个外部中断,具有16级可编程中断;stm32f103的更少。
  #NVIC和EXTI的关系:NVIC是Cortex-M3核心的一部分,关于它的资料不在《STM32的技术参考手册》中,应查阅ARM公司的《Cortex-M3技术参考手册》
  Cortex-M3的向量中断统一由NVIC管理
  EXTI是ST公司在其STM32产品上扩展的外中断控制。它负责管理映射到GPIO引脚上的外中断和片内几个集成外设的中断(PVD,RTC alarm,USB wakeup,ethernet wakeup),以及软件中断。其输出最终被映射到NVIC的相应通道。因此,配置EXTI中断的过程必然包含对NVIC的配置,例如下面配置EXTI0的过程,就要首先配置EXTI控制器(使能相应的中断线,选择中断/事件模式,触发边沿极性),然后再配置NVIC控制器(EXTI0映射在NVIC上的通道号,中断优先级,中断屏蔽状态):
  NVIC(管理内核外设和片上外设所有的功能):具体描述在CM3手册
  寄存器:
  1, 使能与除能寄存器NVIC_ISER[8]/ NVIC_ICER[8]
  2, 悬起与“解悬”寄存器NVIC_ISPR[8]/ NVIC_ICPR[8]
  3, 优先级寄存器NVIC_IPR[60]
  中断优先级寄存器为60个32位寄存器,st的结构体中用了240个8位的字节数组NVIC-》IP[240]来映射,每一个对应一个中断的优先级。
  抢断优先级;
  亚优先级:
  4, 活动状态寄存器NVIC_IABR[8]
  5, 外部中断/事件控制器(EXTI;AFIO)
  GPIO 的管教 GPIOx.0~GPIOx.15(x=A,B,C,D,E, F,G)分别对应中断线 0~15。这样每个中断线对应了最多 7 个 IO 口,以线 0 为例:它对应了 GPIOA.0、 GPIOB.0、 GPIOC.0、 GPIOD.0、GPIOE.0、 GPIOF.0、 GPIOG.0。而中断线每次只能连接到 1 个 IO 口上,这样就需要通过配置来决定对应的中断线配置到哪个GPIO 上了。
  1, voidGPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
  该函数将GPIO 端口与中断线映射起来
  //初始化结构体:
  typedef struct
  {
  uint32_t EXTI_Line; //第一个参数是中断线的标号,取值范围为
  EXTI_Line0~EXTI_Line15
  EXTIMode_TypeDef EXTI_Mode; //(第二个参数是中断模式,可选值为中断EXTI_Mode_Interrupt 和事件 EXTI_Mode_Event。)
  EXTITrigger_TypeDef EXTI_Trigger; //第三个参数是触发方式,可以是下降沿触发EXTI_Trigger_Falling,上升沿触发 EXTI_Trigger_Rising,或者任意电平(上升沿和下沿) 触发EXTI_Trigger_Rising_Falling,
  FunctionalState EXTI_LineCmd; 最后一个参数就是使能中断线
  了。
  }EXTI_InitTypeDef;
  #EXTI寄存器
  1, 中断屏蔽寄存器(EXTI_IMR)
  2, 事件屏蔽寄存器(EXTI_EMR)
  3, 上升沿触发选择寄存器(EXTI_RTSR)
  4, 下降沿触发选择寄存器(EXTI_FTSR)
  5, 软件中断事件寄存器(EXTI_SWIER)
  6, 挂起寄存器(EXTI_PR)
  7, 外部中断/事件寄存器映像
  8, STM32中,每一个GPIO都可以触发一个外部中断,但是,GPIO的中断是以组位一个单位的,同组间的外部中断同一时间只能使用一个。比如说,PA0,PB0,PC0,PD0,PE0,PF0,PG0这些为1组,如果我们使用PA0作为外部中断源,那么别的就不能够再使用了,在此情况下,我们只能使用类似于PB1,PC2这种末端序号不同的外部中断源。每一组使用一个中断标志EXTIx。
  9, EXTI0 – EXTI4这5个外部中断有着自己的单独的中断响应函数,
  10, EXTI5-9共用一个中断响应函数,
  11, EXTI10-15共用一个中断响应函数。
  #AFIO //外部中断的输入线选
  1, 事件控制寄存器(AFIO_EVCR)
  2, 复用重映射和调试I/O配置寄存器(AFIO_MAPR)
  3, 外部中断配置寄存器 1(AFIO_EXTICR1)
  4, 外部中断配置寄存器 2(AFIO_EXTICR2)
  5, 外部中断配置寄存器 3(AFIO_EXTICR3)
  6, 外部中断配置寄存器 4(AFIO_EXTICR4)
  #USART串口:
  #寄存器:
  1, 状态寄存器(USART_SR)
  2, 数据寄存器(USART_DR){ 8位有效 }
  3, 波特比率寄存器(USART_BRR)
  4, 控制寄存器 1(USART_CR1)
  5, 控制寄存器 2(USART_CR2)
  6, 控制寄存器 3(USART_CR3)
  7, 保护时间和预分频寄存器(USART_GTPR)
  波特率计算值公式:
  波特率=Fckl/(16*USARTDIV)
  USARTDIV写入到一个寄存器,USART_BRR[11:0][3:0]带小数
  #串口中断标志:
  #TC:
  TC:发送完成 (Transmission complete)
  当包含有数据的一帧发送完成后,并且TXE=1时,由硬件将该位置’1’。如果USART_CR1中的TCIE为’1’,则产生中断。由软件序列清除该位(先读USART_SR,然后写入USART_DR)。 TC位也可以通过写入’0’来清除,只有在多缓存通讯中才推荐这种清除程序。
  0:发送还未完成;
  1:发送完成
  #RXEN:
  RXNE:读数据寄存器非空 (Read data register not empty)
  当RDR移位寄存器中的数据被转移到USART_DR寄存器中,该位被硬件置位。如果
  USART_CR1寄存器中的RXNEIE为1,则产生中断。对USART_DR的读操作可以将该位清
  零。 RXNE位也可以通过写入0来清除,只有在多缓存通讯中才推荐这种清除程序。
  0:数据没有收到;
  1:收到数据,可以读出。
  模拟/数字转换(ADC)
  表62 ADC引脚
  名称
  信号类型
  注解
  VREF+
  输入,模拟参考正极
  ADC使用的高端/正极参考电压, 2.4V ≤ VREF+ ≤ VDDA
  VDDA(1)
  输入,模拟电源
  等效于VDD的模拟电源且: 2.4V ≤ VDDA ≤ VDD(3.6V)
  VREF-
  输入,模拟参考负极
  ADC使用的低端/负极参考电压, VREF- = VSSA
  VSSA(1)
  输入,模拟电源地
  等效于VSS的模拟电源地
  ADCx_IN[15:0]
  模拟输入信号
  16个模拟输入通道
  1. VDDA和VSSA应该分别连接到VDD和VSS。
  通过设置ADC_CR2寄存器的ADON位可给ADC上电。当第一次设置ADON位时,它将ADC从断电状态下唤醒。ADC上电延迟一段时间后(tSTAB),再次设置ADON位时开始进行转换。通过清除ADON位可以停止转换,并将ADC置于断电模式。
  #ADC寄存器
  1,ADC状态寄存器(ADC_SR)
  2, ADC控制寄存器 1(ADC_CR1)
  3, ADC控制寄存器 2(ADC_CR2)
  4, ADC采样时间寄存器 1(ADC_SMPR1)
  5, ADC采样时间寄存器 2(ADC_SMPR2)
  6, ADC注入通道数据偏移寄存器x(ADC_JOFRx)(x=1..4)
  7, ADC看门狗高阀值寄存器(ADC_HTR)
  8, ADC看门狗低阀值寄存器(ADC_LRT)
  9, ADC规则序列寄存器 2(ADC_SQR2)
  10, ADC规则序列寄存器 3(ADC_SQR3)
  11,ADC规则序列寄存器 1(ADC_SQR1)
  #ADC 工作参数具体配置为:独立模式、单通道采集不需要扫描、启动连续转换、使用内部软件触发无需外部触发事件、使用右对齐数据格式、转换通道为1,并调用 ADC_Init函数完成 ADC 工作环境配置
  #RCC_ADCCLKConfig()函数用来配置 ADC 的工作时钟,接收一个参数,设置的是PCLK2的分频系数,ADC 的时钟最大不能超过 14M。
  #ADC_RegularChannelConfig 函数用来绑定 ADC 通道的转换顺序和采样时间。它接收 4个形参,第一个形参选择 ADC外设,可为ADC1、 ADC2或 ADC3;第二个形参通道选择,总共可选 18 个通道;第三个形参为通道的转换顺序,可选为1 到 16;第四个形参为采样周期选择,采样周期越短, ADC 转换数据输出周期就越短但数据精度也越低,采样周期越长,ADC 转换数据输出周期就越长同时数据精度越高。
  #ADC_Cmd 函数控制 ADC 转换启动和停止。最后,在 ADC校准之后调用 ADC_SoftwareStartConvCmd函数进软件触发 ADC开始转换
  #我们使用 ADC_ITConfig 函数使能 ADC 转换完成中断,并在中断服务函数中读取转换结果数据
  #ADC校准可以使数据更加准确
  ADC_ResetCalibration(ADC1);
  while (ADC_GetResetCalibrationStatus(ADC1));
  ADC_StartCalibration(ADC1);
  while (ADC_GetCalibrationStatus(ADC1));
  #DMA
  #DMA:把数据从一个地方搬到另外一个地方
  #DMA寄存器
  1, DMA中断状态寄存器(DMA_ISR)
  2, DMA中断标志清除寄存器(DMA_IFCR)
  3, DMA中断标志清除寄存器(DMA_IFCR)
  4, DMA中断标志清除寄存器(DMA_IFCR)
  5, DMA通道x配置寄存器(DMA_CCRx)(x= 1…7)
  6, DMA通道x传输数量寄存器(DMA_CNDTRx)(x= 1…7)
  7, DMA通道x外设地址寄存器(DMA_CPARx)(x= 1…7)
  9, DMA通道x存储器地址寄存器(DMA_CMARx)(x= 1…7)
  DMA 具有 12 个独立可编程的通道,其中 DMA1 有 7 个通道, DMA2 有 5 个通道,每个通道对应不同的外设的 DMA 请求。虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个。
  #通道优先级:
  当发生多个 DMA 通道请求时,就意味着有先后响应处理的顺序问题,这个就由仲裁
  器也管理。仲裁器管理 DMA 通道请求分为两个阶段。第一阶段属于软件阶段,可以在
  DMA_CCRx 寄存器中设置,有 4 个等级:非常高、高、中和低四个优先级。第二阶段属于硬件阶段,如果两个或以上的DMA 通道请求设置的优先级一样,则他们优先级取决于通道编号,编号越低优先权越高,比如通道 0 高于通道 1。在大容量产品和互联型产品中,DMA1控制器拥有高于DMA2 控制器的优先级。
  #源和目标地址存储的数据宽度还必须一致
  #存储器的数据宽度由 DMA_CCR 的 MSIZE[1:0]配置,可以是 8/16/32 位
  #我们可以一次性给电脑发送很多数据,具体多少由DMA_CNDTR 配置,这是一个 32 #位的寄存器,一次最多只能传输 65535 个数据。
  #外设的地址指针由 DMA_CCRx 的 PINC 配置,存储器的地址指针由 MINC 配置。
  #数据什么时候传输完成,我们可以通过查询标志位或者通过中断的方式来鉴别。每个
  DMA 通道在 DMA 传输过半、传输完成和传输错误时都会有相应的标志位,如果使能了该类型的中断后,则会产生中断。
  #传输完成还分两种模式,是一次传输还是循环传输,一次传输很好理解,即是传输一
  次之后就停止,要想再传输的话,必须关断 DMA 使能后再重新配置后才能继续传输。循环传输则是一次传输完成之后又恢复第一次传输时的配置循环传输,不断的重复。
  #注意!!在配置DMA的时候一定要使用DMA_SetCurrDataCounter()函数来设置传输的数据个数;
  #DAC: 数字/模拟转换模块(DAC)是12位数字输入,电压输出的数字/模拟转换器。 DAC可以配置为8位或12位模式,也可以与DMA控制器配合使用。 DAC工作在12位模式时,数据可以设置成左对齐或右对齐。DAC模块有2个输出通道,每个通道都有单独的转换器。在双DAC模式下, 2个通道可以独立地进行转换,也可以同时进行转换并同步地更新2个通道的输出。 DAC可以通过引脚输入参考电压VREF+以获得更精确的转换结果。
  #DAC功能描述:
  1, 使能DAC通道
  2, 使能DAC输出缓存: DAC集成了2个输出缓存,可以用来减少输出阻抗,无需外部运放即可直接驱动外部负载。每个DAC通道输出缓存可以通过设置DAC_CR寄存器的BOFFx位来使能或者关闭。
  3, DAC数据格式
  单DAC通道x,有3种情况:8位数据右对齐:
  12位数据左对齐:
  12位数据右对齐:
  DAC输出 = VREF x (DOR / 4095)。
  #DAC1-》PA4
  #DAC2-》PA5
  #PWM
  STM32 的定时器除了 TIM6 和 7。其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达4路的 PWM 输出,这样, STM32 最多可以同时产生 30 路 PWM 输出。
  110: PWM模式1- 在向上计数时,一旦TIMx_CNT《TIMx_CCR1时通道1为有效电平,否则为无效电平;在向下计数时,一旦TIMx_CNT》TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。
  111: PWM模式2- 在向上计数时,一旦TIMx_CNT《TIMx_CCR1时通道1为无效电平,否则为有效电平;在向下计数时,一旦TIMx_CNT》TIMx_CCR1时通道1为有效电平,否则为无效电
  平。
  PWM模式:
  1, 计数器(TIMx_CNT)
  2, 预分频器(TIMx_PSC)
  3, 自动重装载寄存器(TIMx_ARR)
  4, 捕获/比较寄存器 1(TIMx_CCR1)
  5, 捕获/比较寄存器 2(TIMx_CCR2)
  6, 捕获/比较寄存器 3(TIMx_CCR3)
  7, 捕获/比较寄存器 4(TIMx_CCR4)
  8, DMA控制寄存器(TIMx_DCR)
  9, 连续模式的DMA地址(TIMx_DMAR)
  10, 控制寄存器 1(TIMx_CR1)
  11, 控制寄存器 2(TIMx_CR2)
  12, 从模式控制寄存器(TIMx_SMCR)
  13, DMA/中断使能寄存器(TIMx_DIER)
  14, 状态寄存器(TIMx_SR)
  15, 事件产生寄存器(TIMx_EGR)
  16, 捕获/比较模式寄存器 1(TIMx_CCMR1)
  17, 捕获/比较模式寄存器 2(TIMx_CCMR2)
  18, 捕获/比较使能寄存器(TIMx_CCER)
  这里我们讲解一下与我们要求相关的几个成员变量:
  参数 TIM_OCMode 设置模式是 PWM 还是输出比较,这里我们是 PWM 模式。
  参数 TIM_OutputState用来设置比较输出使能,也就是使能PWM 输出到端口。
  参数 TIM_OCPolarity用来设置极性是高还是低。
  其他的参数 TIM_OutputNState, TIM_OCNPolarity, TIM_OCIdleState和 TIM_OCNIdleState是高级定时器TIM1 和 TIM8 才用到的。
  简单的说 STM32的 io 有3个功能一个是默认的一个是复用一个是重映射功能(这个其实也属于复用)
  如果配置成复用 则将使用第2个功能 如果配置成复用 同时 相应的重映射配置了 则将使用第3个功能
  通常一个口的 复用+重映射有好多 不止两个 这时候就看你使能哪个设备了(哪个被使能就用哪个)
  开复用 + 使能设备+ 是否重映射就可以决定这个io口到底使用哪个功能
  一般芯片的dma有基本功能。
  1、普通的内存、外设间互传数据,一次性的。
  2、支持链表的,美其名曰“scatter”,内核有struct scatter可以参考。
  说一下注意点:
  dma有burst、burst size、transfer的概念:
  burst:dma实际上是一次一次的申请总线,把要传的数据总量分成一个一个小的数据块。比如要传64个字节,那么dma内部可能分为2次,一次传 64/2=32个字节,这个2(a)次呢,就叫做burst。这个burst是可以设置的。这32个字节又可以分为32位 * 8或者16位*16来传输。
  transfer size:就是数据宽度,比如8位、32位,一般跟外设的FIFO相同。burst size:就是一次传几个 transfer size.
  现在我配置数据宽度为32位。一次传8个32位=32个字节。
  那么如果总长度为128字节,那么实际dma设置的长度为 128/32 = 4.
  #SPI:
  #相位:对应着数据采样是在第几个边沿(edge),是第一个边沿还是第二个边沿,0对应着第一个边沿,1对应着第二个边沿
  #极性:SPI的CPOL,表示当SCLK空闲的时候,其电平的值是低电平0还是高电平1
  #stm32用于仿真的GPIO口
  在每个STM32的芯片上都有两个管脚BOOT0和BOOT1,这两个管脚在芯片复位时的电平状态决定了芯片复位后从哪个区域开始执行程序,见下表:
  BOOT1=x BOOT0=0 从用户闪存启动,这是正常的工作模式。
  BOOT1=0 BOOT0=1 从系统存储器启动,这种模式启动的程序功能由厂家设置。
  BOOT1=1 BOOT0=1 从内置SRAM启动,这种模式可以用于调试。
  用JTAG口或SWD模式烧写 选择从用户闪存启动。
  用串口ISP模式烧写程序时时选择从系统存储启动
  三、烧写接口
  如果要减小插座的数量,就用SWD模式的仿真,在这个模式下,如果用JLINK只要四根线就可以了,这四根线分别是:3.3V、GND、SWDIO、SWCLK
  其中
  STM32的JTMS/SWDIO接JTAG口的TMS;
  STM32的JTCK/SWCLK接JTAG口的TCK。
  STM32默认启动时PB4、PB3、PA15三个引脚不是普通IO,而是JTAG的复用功能,分别为JNTRST、JTDI、JTDO。
  当我们试用SWD接口调试仿真时,这三个引脚可以用作普通IO。
  具体做法就是禁用JTAG功能。只需使用以下语句即可。
  STM32死区时间:(完全正确)
  STM32高级定时器死区时间设置探究
  一、死区设置位置:决定死区时间设置的位是‘刹车和死区寄存器
  TIM1-》BDTR’中的DTG[7:0],设置范围是0x00~0xff。
  二、死区时间设置公式如下:DT为死区持续时间,TDTS为系统时钟周期时长,Tdtg为系统时钟周期时长乘以倍数后的死区设置时间步进值。
  在72M的定时器时钟下TDTS=1/72M=13.89ns.
  所以以第一个公式,死区时间能以13.89ns的步进从0调整到127*13.89ns=1764ns第二个公式则能(64+0)*2*13.89~(64+63)*2*13.89=1777.9ns~3528.88ns换个角度看,就是(128~254)*13.89
  同理,第三个公式就是3555.84ns~7000.56ns
  换个角度看,就是(256~504)*13.89
  第四个公式就是7111.68ns~14001.12ns
  换个角度看,就是(512~1008)*13.89
  综上:死区时间就是不同的公式代表不同范围的死区时间设置,这个范围是互不重叠的。而但是在不同的死区时间范围内死区时间设置步进是不同的。
  若某个系统时钟下的死区时间不够,可以通过改变定时器时钟来改变最大死区时间范围。
  当根据硬件电路的特性定下死区时间后,可以根据目标死区时间范围来找到相应的公式,然后代入公式求解出相应的整数(有时候不一定是整数,那就选择最近的那个),拼接DTG[7:5]+DTG[4:0]即可。
  例子:这样当我需要3us的死区持续时间时,则可这么计算:
  3us在第二个公式决定的死区范围之内。所以选择第二个公式。
  3000/(13.89*2)=108,所以DTG[5:0]=108-64=44,所以DTG=127+44=171=0XabTIM1-》BDTR|=0xab;
  反过来验算//72Mhz,死区时间=13.89nsX108*2=3000us
  经示波器验证,完全正确。
  Byzxx2013.07.18
  STM32 SPI操作Flash(W25Q64)
  先W25Q64介绍:
  板上有个带SPI的FLASH产品,W25Q64,华邦公司,大容量64Mb的,也就是8M字节,
  (W25Q64把这个8M的容量分为128块-Block,每块64K字节,分出16个扇区,每个扇区4K字节) 即就是:W25Q64--8M 一个块--64K 一个扇区4K
  最小擦除单位为一个扇区
  关键点---这样我们需要给W25Q64开辟一个至少4K的缓存区,这样对SRAM要求比较高,要求芯片必须有4K以上SRAM才能很好的操作。(嗯,要开辟缓存区)至于W25Q64的擦写周期10W次、数据保存期限20年,随便用就是了。支持电压2.7~3.6V,直接用给stm32供电的3.3V即可,不多说。W25Q64还有一点参数:支持标准的SPI,还支持双输出/四输出的SPI,最大SPI时钟可以到80Mhz(双输出时相当于160Mhz,四输出时相当于320M),更多的W25Q64的介绍,请参考W25Q64的DATASHEET。
  嗯,我们的stm32可以用,先用着。
  stm32对W25Q64
  读FLASH的时候,按地址,及要读的长度,读出来放在数据存储区即可
  写FLASH的时候,要考虑扇区剩余大小,写的数据长度控制
  if(NumByteToWrite《=secremain)secremain=NumByteToWrite;//
  并且,里面已经有数的话,要先擦除这个扇区再写。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分