野火STM32F103学习笔记

相关知识点总结:

  1. ISP(In-System Programming):用于对已经安装到目标系统中的芯片进行编程或烧录。IAP(In-Application Programming):允许嵌入式设备内部的应用程序或固件对自身进行编程或更新。ICP(In-Circuit Programming):用于在组装完成的电路板上,对已经焊接的芯片进行编程。(stm32串口1才具有下载功能)
  2. JTAG:JTAG接口是一种并行接口,通常由4条或更多的信号线组成(TCK、TMS、TDI和TDO)。它广泛应用于集成电路的测试和调试,同时也用于嵌入式系统的编程和调试。SWD:SWD接口是一种串行接口,只需要2条信号线(SWCLK和SWDIO)。SWD接口较JTAG更简单,因为它使用更少的信号线,适用于资源受限或尺寸较小的嵌入式系统。J-Link是一款由SEGGER Microcontroller开发的高性能调试和编程解决方案。它是一种硬件调试器/编程器,通常用于嵌入式系统的开发、调试和编程。J-Link支持多种接口标准,如JTAG、SWD、SWO等,可以与各种不同类型的微控制器和处理器进行通信。
  3. IP(Intellectual Property)厂商和SOC(System-on-Chip)厂商区别:IP厂商和SoC厂商在芯片产业链中分别扮演不同的角色。IP厂商专注于设计和授权IP核心,为SoC设计提供基础技术。而SoC厂商负责将多个IP核心和其他组件集成在一起,并进行SoC芯片的设计、制造和销售。两者的合作和协作有助于推动芯片设计和制造的发展,加快新产品的推出速度,同时也满足不同市场需求。
  4. 微控制器(MCU)和微处理器(CPU)区别:后者一般有内存管理单元MMU,且需要跑操作系统,前者是裸机,微控制器是一种单芯片系统,适用于嵌入式控制应用,而微处理器是一个单独的CPU芯片,用于通用计算任务。
  5. stm32的程序是烧写到Block0中的FLASH 里面的,stm32f10xvet6的FLASH为512KB大小。Keil5中三类擦除的区别:Erase Full Chip(全片擦除)是擦除整个Flash存储器,清除所有数据;Erase Sector(扇区擦除)是只擦除需要烧写的程序所在的扇区,其他数据保留;Do Not Erase(不擦除)是不执行擦除操作,直接烧写新程序,可能导致旧数据被覆盖或冲突。
  6. 模拟输入(可以接收连续范围内的电压信号,不进行数字化处理,保持输入电压的模拟形式。)、上下拉输入(上下拉输入是指输入引脚通过内部或外部上拉电阻或下拉电阻连接到电源或地,以确定引脚的默认电平状态。在没有外部信号驱动时,引脚会被拉向特定的电平状态,从而避免漂浮(Floating)状态。)和浮空输入(浮空输入是指输入引脚没有被连接到任何特定电平状态的电源或地,处于未定义状态。在浮空状态下,输入引脚可能会受到周围环境的电磁干扰,导致不可预测的输出结果。),模拟输入适用于采集连续范围内的电压信号。上下拉输入适用于保持输入引脚在特定电平状态的输入设备。浮空输入是一个应该避免的状态,因为它容易受到外部干扰,导致不稳定的输出。
  7. 推挽输出(推挽输出能主动提供高低电平,适用于直接驱动负载的场景。而开漏输出只能提供低电平,需要外部上拉电阻来提供高电平,适用于多个输出信号共享一个总线的场景。)和开漏输出(开漏输出是指输出引脚只能被拉低(连接到地电压),而不能被主动拉高。开漏输出不具备主动输出高电平的能力,需要外部上拉电阻来提供高电平。)。
  8. CMSIS代表Cortex Microcontroller Software Interface Standard(Cortex微控制器软件接口标准)。它是ARM公司(现在是ARM Limited)提供的一套软件接口标准,旨在为Cortex-M系列处理器的开发者提供一致的编程接口。
  9. 在大多数嵌入式系统和单片机的程序中,main函数通常被设计为一个无限循环。这种设计方式是为了保持系统持续运行并执行特定的任务,直到发生特定条件或错误导致程序终止。
  10. 位带操作(Bit-banding Operation)是一种特殊的嵌入式系统技术,用于单独访问处理器内存中的特定位或比特位。它的作用是提供一种更高效、更快速的方法来访问单个位,而不必使用传统的位操作指令。在传统的位操作中,要访问或修改一个特定的位,通常需要使用位操作指令,例如在C语言中使用位掩码(bit masking)和移位运算来设置或清除特定位。然而,这种方法可能需要多条指令和多次访问内存,因而效率较低。位带操作通过将每个位映射到一个专门的地址,使得可以直接对某个位进行读写操作,从而节省了指令的执行时间。它通过两个区域来实现这种映射:位带区(支持位带操作的地址区)和位带别名区。(两个区域的内容是同步变化的)
  11. stm32启动文件由汇编编写,是系统上电复位后第一个执行的程序。主要做了以下工作:初始化堆栈指针SP=_initial_sp;初始化PC指针=Reset_Handler;初始化中断向量表;配置系统时钟;调用C库函数 _main 初始化用户堆栈,从而最终调用 main 函数去到C程序。
  12. 中断向量表存放在FLASH的0地址处(0x0800 0000处),里面记录各种中断类型的中断服务程序入口地址,每个条目占四个字节,0号类型比较特殊,它记录的是复位后主堆栈指针MSP初值,表示当前的主堆栈的栈顶地址。
  13. 无源晶振就是一个晶体,必须要结合外围电路构成一个振荡器才能输出特定频率的信号,而这个振荡器是需要提供电源的。像MCU可以用无源晶振是因为其内部集成有构成振荡器的电路,晶体不好集成就只好外加了。有源晶振才是真正意义上的一个振荡器,它里面包含了晶体和外围电路,只要外部提供一个电压源,就可以直接输出信号。
  14. stm32的堆栈存放在SRAM中,代码和常量(如const)存放在FLASH中。keil5中的输出信息Program Size: Code=1632 RO-data=336 RW-data=20 ZI-data=6028:其中Code存储代码,RO-data存储const常量和指令,RW-data存储初始值不为0的全局变量、静态变量,ZI-data存储初始值为0的全局变量、静态变量。前两者存储在FLASH中,后两者存储在SRAM中。
  15. 在STM32微控制器中,GPIO外部中断线(EXTI)的时钟使能与其他外设不同,不需要显式地使能时钟。这是因为EXTI功能的时钟是由系统时钟(SYSCLK)提供的,而不是由外设时钟总线(APB1或APB2)控制的。
  16. 静态随机存储器SRAM(用晶体管存储信息不需要刷新)一般采用异步通信方式,一般被用作高速缓存。动态存储器DRAM(用电容存储信息需要刷新)一般采用同步通信方式,即SDRAM,一般被用作内存。为了进一步提高 SDRAM 的通讯速度,人们设计了 DDR SDRAM 存储器 (Double Data Rate SDRAM)。它的存储特性与 SDRAM 没有区别,但 SDRAM 只在上升沿表示有效数据,在 1 个时钟周期内,只能表示 1 个有数据;而 DDRSDRAM 在时钟的上升沿及下降沿各表示一个数据,也就是说在 1 个时钟周期内可以表示 2 位数据,在时钟频率同样的情况下,提高了一倍的速度。至于 DDRII 和 DDRIII,它们的通讯方式并没有区别,主要是通讯同步时钟的频率提高了。
  17. ROM的分类:MASK(掩膜) ROM 就是正宗的“Read Only Memory”,存储在它内部的数据是在出厂时使用特殊工艺固化的,生产后就不可修改。OTPROM(One Time Programable ROM) 是一次可编程存储器。这种存储器出厂时内部并没有资料,用户可以使用专用的编程器将自己的资料写入,但只能写入一次,被写入过后,它的内容也不可再修改。EPROM(Erasable Programmable ROM) 是紫外线可重复擦写的存储器。EEPROM(Electrically Erasable Programmable ROM) 是电可擦除存储器。 EEPROM 可以重复擦写,它的擦除和写入都是直接使用电路控制,不需要再使用外部设备来擦写。而且可以按字节为单位修改数据,无需整个芯片擦除。现在主要使用的 ROM 芯片都是 EEPROM。FLASH闪存只能按块擦除,NOR FLASH可按字节读写,随机存储,地址线和数据线分离,因此NOR FLASH支持XIP(executed in place)本地执行,操作系统可以不用将内核或执行代码拷贝到内存,而直接在代码的存储空间直接运行。NAND FLASH只能按块读写,连续存储,共用地址数据线,FLASH的写操作只能将1变为0,而不能将0变为1,擦除之后,FLASH中是全1的状态,若想将0变为1则只能通过擦除操作,擦除一般按照最小单位进行擦除,一般为扇区。
  18. IIC的总线通过上拉电阻接到电源,当 I2C 设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。当通信时输出低电平表示0,输出高阻态表示1,所以GPIO输出模式一般选择开漏输出(IIC协议支持多个主设备与多个从设备在一条总线上, 如果不用开漏输出, 而用推挽输出, 会出现主设备之间短路的情况。)。
  19. 在向EEPROM存储整型、浮点型、字符串等数据时和存储字节数据是一样的,只要按%d、%f、%s打印输出就可以得到一样的结果,这只是C语言编码解码方式不同,存储的实际二进制数据并没有改变。
  20. 系统初始化时会分配栈的大小,函数中数组分配太大会导致栈溢出,一般会进入硬件中断HardFault,导致程序无法正常进行下去。
  21. 不同逻辑分区可以做不同的文件系统,对硬盘的稳定性没啥影响,不同的文件系统可以简单点认为是操作系统对文件的组织和管理方式不同。
  22. 操作系统启动过程:电源开启,电脑启动BIOS(BIOS (Basic Input and Output System)基本输入-输出系统是一小段嵌入到主板芯片ROM上的代码,他也是一个系统。当电脑插上电,首先运行的第一个系统就是BIOS),BIOS读取第一个扇区的MBR,MBR看自己内部有没有开机管理程序(若没有就是没装系统则开机失败),有的话,看看选单里面有啥东西,(比如安装了Linux和Windows),自身的开机管理程序是Windows的,并且可以转发到另一个开机管理程序。那么选单里就有两个选项,载入Windows和载入Linux,而载入Linux实际上是两个步骤,先转发到Linux开机管理程序的位置,然后由Linux的开机管理程序,载入Linux系统核心。
  23. FAT文件系统之所以有12,16,32不同的版本之分,其根本在于FAT表用来记录任意一簇链接的二进制位数的长度不同。以FAT16为例,每一簇在FAT表中占据 2字节(二进制16位,FAT32采用4字节32位记录)。所以,FAT16最大可以表示的簇号为0xFFFF(十进制的65535),以32K为簇的大小的话,FAT16可以管理的最大磁盘空间为:32KB×65535=2048MB,这就是为什么 FAT16 不支持超过 2GB 分区的原因。(FAT32支持长文件名,而FAT16只支持短文件名)
  24. FSMC是Flexible Static Memory Controller的缩写,译为灵活的静态存储控制器。它可以用于驱动包括SRAM、NOR FLASH以及NAND FLSAH类型的存储器,不能驱动如SDRAM这种动态的存储器而FMC外设,支持控制SDRAM存储器。
  25. 8080 时序也叫因特尔总线,一般用在mcu和lcd的通信上,相关引脚为:CS:片选信号、RS:数据或者命令管脚(即控制传输的是命令还是数据,一般为1表示数据读写,为0表示命令读写)、WR写使能引脚、RD读使能引脚、DB[x:0]:数据地址线、RST:复位引脚、BL:LCD背光引脚等(可参考野火开发指南第27章)。
  26. VGA时序:液晶屏的水平同步信号HSYNC用来在一行像素数据传送完成后开始下一行,垂直同步信号VSYNC用来在一帧数据传送完成后开始下一帧,可以检测垂直同步信号来检测帧率。
  27. ASCII码表分为两部分,第一部分是控制字符或通讯专用字符,它们的数字编码从0~31,它们并没有特定的图形显示,但会根据不同的应用程序,而对文本显示有不同的影响。ASCII码的第二部分包括空格、阿拉伯数字、标点符号、大小写英文字母以及“DEL(删除控制)”,这部分符号的数字编码从32~127,除最后一个DEL符号外,都能以图形的方式来表示,它们属于传统文字书写系统的一部分。GB2312标准把ASCII码表127号之后的扩展字符集直接取消掉,并规定小于127的编码按原来ASCII标准解释字符。当2个大于127的字符连在一起时,就表示1个汉字,第1个字节使用 (0xA1-0xFE) 编码,第2个字节使用(0xA1-0xFE)编码,这样的编码组合起来可以表示了7000多个符号。在这些编码里,还把数学符号、罗马字母、日文假名等都编进表中,就连原来在ASCII里原本就有的数字、标点以及字母也重新编了2个字节长的编码,这就是平时在输入法里可切换的“全角”字符,而标准的ASCII码表中127号以下的就被称为“半角”字符。在GB2312编码的实际使用中,有时会用到区位码的概念。GB2312编码对所收录字符进行了“分区”处理,共94个区,每区含有94个位,共8836个码位。而区位码实际是GB2312编码的内部形式,它规定对收录的每个字符采用两个字节表示,第一个字节为“高字节”,对应94个区;第二个字节为“低字节”,对应94个位。所以它的区位码范围是:0101-9494。为兼容ASCII码,区号和位号分别加上0xA0偏移就得到GB2312编码。在区位码上加上0xA0偏移,可求得GB2312编码范围:0xA1A1-0xFEFE。GBK标准在GB2312标准的基础上又增加了14240个新汉字,增加这么多字符,按照GB2312原来的格式来编码,2个字节已经存储不下,所以不再要求第2个字节的编码值必须大于127,只要第1个字节大于127就表示这是一个汉字的开始,这样就做到兼容ASCII和GB2312标准了(可参考野火开发指南第28章)。
  28. 由于各个国家或地区都根据使用自己的文字系统制定标准,同一个编码在不同的标准里表示不一样的字符,各个标准互不兼容,而又没有一个标准能够囊括所有的字符,即无法用一个标准表达所有字符。国际标准化组织(ISO)为解决这一问题,它舍弃了地区性的方案,重新给全球上所有文化使用的字母和符号进行编号,对每个字符指定一个唯一的编号(ASCII中原有的字符编号不变),该编号集(是编号不是编码)被称为被称为Unicode。对Unicode字符集编码,最自然的就是UTF-32方式。编码时,它直接对Unicode字符集里的每个字符都用4字节来表示,转换方式很简单,直接将字符对应的编号数字转换为4字节的二进制数。而UTF-16对Unicode字符编号在0到65535的统一用2个字节来表示,将每个字符的编号转换为2字节的二进制数,即从0x0000到0xFFFF。而由于Unicode字符集在0xD800-0xDBFF这个区间是没有表示任何字符的,所以UTF-16就利用这段空间,对Unicode中编号超出0xFFFF的字符,利用它们的编号做某种运算与该空间建立映射关系,从而利用该空间表示4字节扩展。UTF-8也是一种变长的编码方式,它的编码有1、2、3、4字节长度的方式,每个Unicode字符根据自己的编号范围去进行对应的编码。它的编码符合以下规律:对于UTF-8单字节的编码,该字节的第1位设为0(从左边数起第1位,即最高位),剩余的位用来写入字符的Unicode编号。即对于Unicode编号从0x0000 0000-0x0000 007F的字符,UTF-8编码只需要1个字节,因为这个范围Unicode编号的字符与ASCII码完全相同,所以UTF-8兼容了ASCII码表;对于UTF-8使用N个字节的编码(N>1),第一个字节的前N位设为1,第N+1位设为0,后面字节的前两位都设为10,这N个字节的其余空位填充该字符的Unicode编号,高位用0补足。
  29. 字模的概念,字库及其相关索引文件的制作(利用字模软件,如PCtoLCD,可参考野火视频P86)。
  30. 触摸屏是一种把触摸位置转化成坐标数据的输入设备,根据触摸屏的检测原理,主要分为电阻式触摸屏和电容式触摸屏。电阻屏造价便宜,能适应较恶劣的环境,但它只支持单点触控(一次只能检测面板上的一个触摸位置),触摸时需要一定的压力,使用久了容易造成表面磨损,影响寿命;而电容屏具有支持多点触控、检测精度高的特点,电容屏通过与导电物体产生的电容效应来检测触摸动作,只能感应导电物体的触摸,湿度较大或屏幕表面有水珠时会影响电容屏的检测效果。常见的四线电阻触摸屏有X-、X+、Y-、Y+四个电极,外部电路向这两个涂层可以施加匀强电场或检测电压。(具体原理参考野火开发指南第29章)。
  31. 对于机械按键或者电阻触摸屏的软件消抖可以通过swtich语句构建状态机来实现,具体可以参考野火开发指南第29章。
  32. STM32有两个看门狗,一个是独立看门狗(独立看门狗的时钟由独立的RC振荡器LSI提供,即使主时钟发生故障它仍然有效,非常独立)另外一个是窗口看门狗(窗口看门狗时钟来自PCLK1,PCLK1最大是36M,由RCC时钟控制器开启),独立看门狗号称宠物狗,窗口看门狗号称警犬。独立看门狗用通俗一点的话来解释就是一个12位的递减计数器,当计数器的值从某个值一直减到0的时候,系统就会产生一个复位信号,即 IWDG_RESET。如果在计数没减到0之前,刷新了计数器的值的话,那么就不会产生复位信号,这个动作就是我们经常说的喂狗。独立看门狗一般用来检测和解决由程序引起的故障,比如一个程序正常运行的时间是50ms,在运行完这个程序之后紧接着进行喂狗,我们设置独立看门狗的定时溢出时间为60ms,比我们需要监控的程序50ms多一点,如果超过60ms还没有喂狗,那就说明我们监控的程序出故障了,那么就会产生系统复位,让程序重新运行。窗口看门狗跟独立看门狗一样,也是一个递减计数器不断的往下递减计数,当减到一个固定值 0X40时还不喂狗的话,产生复位,这个值叫窗口的下限,是固定的值,不能改变。窗口看门狗的计数器的值在减到某一个数之前喂狗的话也会产生复位,这个值叫窗口的上限,上限值可以独立设置。窗口看门狗计数器的值必须在上窗口和下窗口之间才可以喂狗。
  33. SD卡(Secure Digital Memory Card)一般采用的是SPI或SDIO协议进行数据传输(注意SD卡和SD I/O卡的区别,SD I/O卡本身不是用于存储的卡,它是指利用SDIO传输协议的一种外设),一张SD卡内部包括有存储单元、存储单元接口、电源检测、卡及接口控制器和接口驱动器5个部分,SD卡内部寄存器只能通过对应的命令访问。SDIO采用同步通信方式,CLK信号由SDIO主机产生(如stm32,SDIO 不管是从主机控制器向 SD 卡传输,还是 SD 卡向主机控制器传输都只以 CLK 时钟线的上升沿为有效),命令控制线是CMD,SDIO主机通过该线发送命令控制SD卡,如果命令要求SD卡提供应答,SD卡也是通过该线传输应答信息。D0-3是数据线(SD卡最多用四根数据线,输读写数据,SD卡可将D0拉低表示忙状态。SD卡操作过程会使用两种不同频率的时钟同步数据,一个是识别卡阶段时钟频率FOD,最高为400kHz;另外一个是数据传输模式下时钟频率FPP,默认最高为25MHz,如果通过相关寄存器配置使SDIO工作在高速模式,此时数据传输模式最高频率为50MHz(SD卡在这两种模式下的状态转换可参考野火教程相应ppt)。SD数据是以块(Black)形式传输的,数据可以从主机到卡,也可以是从卡到主机。数据块使用CRC位来保证数据传输成功,CRC位由SD卡系统硬件生成。使用4数据线传输时,每次传输4bit数据,每根数据线都必须有起始位(“0”)、终止位(“1”)以及CRC位,CRC位每根数据线都要分别检查,并把检查结果汇总然后在数据传输完后通过D0线反馈给主机。SD卡数据包有两种格式,一种是常规数据(8bit宽),它先发低字节再发高字节,而每个字节则是先发高位再发低位,另外一种数据包发送格式是宽位数据包格式,对SD卡而言宽位数据包发送方式是针对SD卡SSR(SD状态)寄存器内容发送的,SSR寄存器总共有512bit,在主机发出ACMD13命令后SD卡将SSR寄存器内容通过DAT线发送给主机。SD命令格式固定为48bit(命令部分占6位,一共可表示64种命令),都是通过CMD线连续传输的,数据线不参与,命令有四种类型:无响应广播命令(bc)、带响应广播命令(bcr)、寻址命令(ac)和寻址数据传输命令(adtc)(上述是基本命令,还有特定明林,使用特定命令需要在发送该命令之前发送CMD55命令)。SDIO总共有7个响应类型(代号:R1~R7),其中SD卡没有R4、R5类型响应。特定的命令对应有特定的响应类型,比如当主机发送CMD3命令时,可以得到响应R6,与命令一样,SD卡的响应也是通过CMD线连续传输的,根据响应内容大小可以分为短响应和长响应。短响应是48bit长度,只有R2类型是长响应,其长度为136bit(具体参考野火开发指南第36章和相应ppt)。
  34. CAN协议(Controller Area Network) 是由研发和生产汽车电子产品著称的德国BOSCH公司开发的,并最终成为国际标准(ISO11519),是国际上应用最广泛的现场总线之一。CAN通讯是一种异步通讯,只具有CAN_High和CAN_Low两条信号线,共同构成一组差分信号线,以差分信号的形式进行通讯。分为CAN闭环通讯网络:遵循ISO11898标准的高速、短距离网络,它的总线最大长度为40m,通信速度最高为1Mbps,总线的两端各要求有一个“120欧”的电阻;CAN开环总线网络:遵循ISO11519-2标准的低速、远距离网络,它的最大传输距离为1km,最高通讯速率为125kbps,两根总线是独立的、不形成闭环,要求每根总线上各串联有一个“2.2千欧”的电阻。由于CAN通讯协议不对节点进行地址编码,而是对数据内容进行编码,所以网络中的节点个数理论上不受限制,只要总线的负载足够即可,可以通过中继器增强负载。CAN使用差分信号传输具有抗干扰能力强、时序定位精确等优点。以高速CAN协议为例,当表示逻辑1时(隐性电平),CAN_High和CAN_Low线上的电压均为2.5v,即它们的电压差VH-VL=0V;而表示逻辑0时(显性电平,显性是指当总线上同时有1和0信号存在时,最后体现为0),CAN_High的电平为3.5V,CAN_Low线的电平为1.5V,即它们的电压差为VH-VL=2V。CAN通讯是半双工的,收发数据需要分时进行。在CAN的通讯网络中,因为共用总线,在整个网络中同一时刻只能有一个通讯节点发送信号,其余的节点在该时刻都只能接收(CAN中没有主从机的说法)。由于CAN属于异步通讯,没有时钟信号线,连接在同一个总线网络中的各个节点会像串口异步通讯那样,节点间使用约定好的波特率进行通讯,特别地,CAN还会使用“位同步”的方式来抗干扰、吸收误差,实现对总线电平信号进行正确的采样:位同步即CAN协议把每一个数据位的时序分解成SS段(同步段,只占1Tq)、PTS段、PBS1段、PBS2段,这四段的长度加起来即为一个CAN数据位的长度。分解后最小的时间单位是Tq,而一个完整的位由8~25个Tq组成。CAN共有五种类型的报文:数据帧、遥控帧、错误帧、过载帧和帧间隔(具体参考野火CAN—通讯实验ppt)。CAN通讯的四种工作模式:正常模式、静默模式、回环模式和回环静默模式。CAN一次可以传送0-8个字节的数据。
  35. MPU6050陀螺仪:三个坐标系:地球坐标系是以地球球心为原点,Z轴沿地球自转轴方向,X、Y轴在赤道平面内的坐标系;地理坐标系的原点在地球表面(或运载体所在的点),Z轴沿当地地理垂线的方向(重力加速度方向),XY轴沿当地经纬线的切线方向;载体坐标系以运载体的质心为原点,一般根据运载体自身结构方向构成坐标系,如Z轴上由原点指向载体顶部,Y轴指向载体头部,X轴沿载体两侧方向。利用重力可以检测俯仰角和横滚角但是无法检测偏航角,偏航角可以用磁力计来检测。MMPU6050是一种六轴传感器模块,能同时检测三轴加速度(可按1000HZ输出)、三轴陀螺仪(三轴角速度,可按8000HZ输出)的运动数据以及温度数据,采用I2C通信,其内部的DMP模块(Digital Motion Processor数字运动处理器),可对传感器数据进行滤波、融合处理,它直接通过I2C接口向主控器输出姿态解算后的姿态数据(可按200HZ输出),降低主控器的运算量。
  36. RS-485通讯协议:与CAN类似,RS-485是一种工业控制环境中常用的通讯协议,它具有抗干扰能力强、传输距离远的特点。RS-485通讯协议由RS-232协议改进而来,协议层不变,只是改进了物理层,因而保留了串口通讯协议应用简单的特点。RS-485与RS-232的差异只体现在物理层上,它们的协议层是相同的,也是使用串口数据包的形式传输数据。RS-485通讯网络的最大传输距离可达1200米,总线上可挂载128个通讯节点,而由于RS-485网络只有一对差分信号线,它使用差分信号来表达逻辑,当AB两线间的电压差为+2V~+6V时表示逻辑1,当电压差为-6V~-2V 表示逻辑0,在同一时刻只能表达一个信号,所以它的通讯是半双工形式的。对于RS-232,他类似于串口,采用全双工通信,有TXD和RXD,电压为-15V~-3V时表示逻辑1,当电压差为+3V~+15V 表示逻辑0,通讯距离100米以内,只能有两个节点通讯。
  37. stm32的电源:STM32芯片主要通过引脚VDD从外部获取电源,在它的内部具有电源监控器用于检测VDD的电压,当检测到VDD的电压低于阈值VPOR及VPDR时,无需外部电路辅助,STM32芯片会自动保持在复位状态,防止因电压不足强行工作而带来严重的后果。除此之外,STM32还提供了可编程电压检测器PVD,它也是实时检测VDD的电压,当检测到电压低于编程的VPVD阈值时,会向内核产生一个PVD中断(EXTI16线中断)以使内核在复位前进行紧急处理。该电压阈值可通过电源控制寄存器PWR_CSR设置。STM32的电源系统主要分为备份域电路、内核电路以及ADC电路三部分(具体参考电源章节相关ppt1)。按功耗由高到低排列,STM32具有运行、睡眠、停止和待机四种工作模式。运行模式即正常运行状态,后面三种模式是低功耗模式,这三种低功耗模式层层递进,运行的时钟或芯片功能越来越少,因而功耗越来越低。睡眠:内核停止(睡眠和停止模式都会使程序停止运行,区别在于时钟是否停止),但所有外设包括M3核心的外设,如NVIC、系统时钟(SysTick)等仍在运行,内核时钟关,对其他时钟和ADC时钟无影响;停止:所有的时钟都已停止,所有的I/O及寄存器值都保持在停止前一刻的状态,被唤醒时,stm32使用HIS作为系统时钟(8MHz)继续运行,由于系统时钟会影响很多外设的工作(如串口通信),所以一般在唤醒后会重启HSE时钟;待机:1.8V 电源关闭,待机状态被唤醒后相当于复位芯片,重头开始执行。可通过设置内核寄存器的SLEEPDEEP,PWR_CR寄存器中的PDDS来设置进入哪种低功耗模式,PWR_CR 寄存器的LPDS可以设置调压器工作在正常模式或者低功耗模式。在睡眠模式和停止模式时,WFI(__WFI()是cortex m3的内核指令)和WFE设置是中断唤醒还是事件唤醒,睡眠模式可使用任意中断唤醒,停止模式可使用任意EXTI线的中断唤醒;待机模式下,可通过WKUP引脚(即PA0引脚,使用前要先使能)的上升沿,RTC闹钟、唤醒、入侵、时间戳事件或NRST引脚外部复位及IWDG复位唤醒(具体参考电源章节相关ppt2)。
  38. STM32的RTC外设(Real Time Clock),实质是一个掉电后还继续运行的定时器。从 RTC 的定时器特性来说,它是一个32位的计数器,只能向上计数。它使用的时钟源有三种,
  39. 分别为高速外部时钟的128分频(HSE/128)、低速内部时钟LSI以及低速外部时钟LSE;使HSE分频时钟或LSI的话,在主电源VDD掉电的情况下,这两个时钟来源都会受到影响,因此没法保证RTC正常工作。因此RTC一般使用低速外部时钟LSE,在设计中,频率通常为实时时钟模块中常用的32.768KHz,这是因为32768 = 2^15,分频容易实现,所以它被广泛应用到RTC模块。UNIX时间戳:UNIX计时元年被设置为格林威治时间1970年1月1日0时0分0秒,大概是为了纪念UNIX的诞生的时代吧,而UNIX时间戳即为当前时间相对于UNIX计时元年经过的秒数。
  40. 编译:MDK软件使用的编译器是armcc(编译c/c++文件)和armasm(编译汇编文件),它们根据每个c/c++和汇编源文件编译成对应的以“.o”为后缀名的对象文件(Object Code,也称目标文件),其内容主要是从源文件编译得到的机器码,包含了代码、数据以及调试使用的信息;链接:链接器armlink把各个.o文件及库文件链接成一个映像文件“.axf”或“.elf”;格式转换:一般来说Windows或Linux系统使用链接器直接生成可执行映像文件elf后,内核根据该文件的信息加载后,就可以运行程序了,但在单片机平台上,需要把该文件的内容加载到芯片上,所以还需要对链接器生成的elf映像文件利用格式转换器fromelf转换成“.bin”或“.hex”文件,交给下载器下载到芯片的FLASH或ROM中。
  41. 在工程的编译提示输出信息中有一个语句“Program Size:Code=xx RO-data=xx RW-data=xx ZI-data=xx”,它说明了程序各个域的大小,编译后应用程序中所有具有同一性质的数据(包括代码)被归到一个域。 Code:即代码域,它指的是编译器生成的机器指令,这些内容被存储到ROM区。RO-data:即只读数据域,它指程序中用到的只读数据,这些数据被存储在ROM区,因而程序不能修改其内容。例如C语言中const关键字定义的变量就是典型的RO-data。RW-data:即可读写数据域,它指初始化为“非0值”的可读写数据,程序刚运行时,这些数据具有非0的初始值,且运行的时候它们会常驻在RAM区,因而应用程序可以修改其内容。例如C语言中使用定义的全局变量,且定义时赋予“非0值”给该变量进行初始化。ZI-data:即0初始化数据,它指初始化为“0值”的可读写数据域,它与RW-data的区别是程序刚运行时这些数据初始值全都为0,而后续运行过程与RW-data的性质一样。例如C语言中使用定义的全局变量,且定义时赋予“0值”给该变量进行初始化(若定义该变量时没有赋予初始值,编译器会把它当ZI-data来对待,初始化为0)。ZI-data的栈空间及堆空间:在C语言中,函数内部定义的局部变量属于栈空间,进入函数的时候从向栈空间申请内存给局部变量,退出时释放局部变量,归还内存空间。而使用malloc动态分配的变量属于堆空间。在程序中的栈空间和堆空间都是属于ZI-data区域的,这些空间都会被初始值化为0值。编译器给出的ZI-data占用的空间值中包含了堆栈的大小(经实际测试,若程序中完全没有使用malloc动态申请堆空间,编译器会优化,不把堆空间计算在内)。程序在存储状态时(即未运行时),RO节及RW节都被保存在ROM区。当程序开始运行时,内核直接从ROM中读取代码,并且在执行主体代码前,会先执行一段加载代码,它把RW节数据从ROM复制到RAM, 并且在RAM加入ZI节,ZI节的数据都被初始化为0。加载完后RAM区准备完毕,正式开始执行主体程序。STM32的RO区域不需要加载到SRAM,内核直接从FLASH读取指令运行。计算机系统的应用程序运行过程很类似,不过计算机系统的程序在存储状态时位于硬盘,执行的时候甚至会把上述的RO区域(代码、只读数据)加载到内存,加快运行速度,还有虚拟内存管理单元(MMU)辅助加载数据,使得可以运行比物理内存还大的应用程序。而STM32没有MMU,所以无法支持Linux和Windows系统。当程序存储到STM32芯片的内部FLASH时(即ROM区),它占用的空间是Code、RO-data及RW-data的总和,所以如果这些内容比STM32芯片的FLASH空间大,程序就无法被正常保存了。当程序在执行的时候,需要占用内部SRAM空间(即RAM区),占用的空间包括RW-data和ZI-data。在MDK中,我们建立的工程一般会选择芯片型号,选择后就有确定的FLASH及SRAM大小,若代码超出了芯片的存储器的极限,编译器会提示错误,这时就需要裁剪程序了,裁剪时可针对超出的区域来优化。
  42. armcc用来编译c/c++文件,其编译选项可在MDK的魔术棒(Option For Targets)的C/C++栏中设置(下面选项框中的编译命令会相应改变);armasm用来编译汇编文件,其编译选项可在MDK的魔术棒(Option For Targets)的Asm栏中设置;armlink是链接器,它把各个O文件链接组合在一起生成elf格式的axf文件,axf文件是可执行的,其链接选项可在MDK的魔术棒(Option For Targets)的Linker栏中设置;armar工具用于把工程打包成库文件,fromelf可根据axf文件生成hex、bin文件,hex和bin文件是大多数下载器支持的下载文件格式,可在MDK的魔术棒(Option For Targets)的Output栏中设置;MDK的魔术棒(Option For Targets)的User栏提供了三种类型的用户指令输入框,在不同组的框输入指令,可控制指令的执行时间,分别是编译前(Before Compile c/c++ file)、构建前(Before Build/Rebuild)及构建后(After Build/Rebuild)执行。这些指令并没有限制必须是arm的编译工具链,也可以在这里输入其他可执行脚本。
  43. MDK工的部分文件类型如下:Project目录下:*.uvguix是MDK5工程的窗口布局文件;*.uvprojx是MDK5的工程文件,它使用了XML格式记录了工程结构,双击它可以打开整个工程; *.uvoptx是MDK5的工程配置选项,包含debugger、trace configuration、breakpooints以及当前打开的文件。Output目录下:*.lib是库文件;*.dep是整个工程的依赖文件;*.d是对应.o的依赖的文件;*.crf是交叉引用文件,包含了浏览信息(定义、引用及标识符);*.o是可重定位的对象文件(目标文件);*.axf是由armcc编译生成的可执行对象文件,可用于调试,该文件不可重定位;*.elf是由gcc编译生成的文件,功能跟axf文件一样,该文件不可重定位;*.hex是Intel Hex格式的映像文件,可理解为带存储地址描述格式的bin文件;*.bin是二进制格式的映像文件,是纯粹的FLASH映像,不含任何额外信息;*.sct是链接器控制文件(分散加载);*.scr是链接器产生的分散加载文件。Listing目录下:*.map是链接器生成的列表文件,包含存储器映像分布;*.lst是C及汇编编译器产生的列表文件(其他更多文件参考MDK章节对应的ppt4).
  44. *.o、*.elf、*.axf、*.bin及*.hex文件都存储了编译器根据源代码生成的机器码,根据应用场合的不同,它们又有所区别。*.o、*.elf、*.axf以及前面提到的lib文件都是属于目标文件,它们都是使用ELF格式来存储的(可参考《ELF文件格式》),ELF是Executable and Linking Format的缩写,译为可执行链接格式,该格式用于记录目标文件的内容。在Linux及Windows系统下都有使用该格式的文件(或类似格式)用于记录应用程序的内容,告诉操作系统如何链接、加载及执行该应用程序。ELF的目标文件主要有如下三种类型:可重定位的文件(Relocatable File,如MDK的armcc和armasm生成的*.o文件),包含基础代码和数据,但它的代码及数据都没有指定绝对地址,因此它适合于与其他目标文件链接来创建可执行文件或者共享目标文件。 这种文件一般由编译器根据源代码生成;可执行文件(Executable File,如使用gcc编译工具可生成*.elf文件,用armlink生成的是*.axf文件,*.axf文件在*.elf之外,增加了调试使用的信息,其余区别不大) ,它包含适合于执行的程序,它内部组织的代码数据都有固定的地址(或相对于基地址的偏移),系统可根据这些地址信息把程序加载到内存执行。这种文件一般由链接器根据可重定位文件链接而成,它主要是组织各个可重定位文件,给它们的代码及数据全打上地址标号,固定其在程序内部的位置,链接后,程序内部各种代码及数据段不可再重定位(即不能再参与链接器的链接);共享目标文件(Shared Object File):MDK生成的*.lib文件就属于共享目标文件,它可以继续参与链接,加入到可执行文件之中。另外,Linux的动态库文件.so也属于这一类。
  45. hex是Intel公司制定的一种使用ASCII文本记录机器码或常量数据的文件格式,这种文件常常用来记录将要存储到ROM中的数据,绝大多数下载器支持该格式。一个hex文件由多条记录组成,而每条记录由五个部分组成,格式形如“:llaaaatt[dd…]cc”,“:” :每条记录的开头都使用冒号来表示一条记录的开始;ll :以16进制数表示这条记录的主体数据区的长度(即后面[dd…]的长度);aaaa:表示这条记录中的内容应存放到FLASH中的起始地址;tt:表示这条记录的类型,它包含中的各种类型;dd:表示一个字节的数据,一条记录中可以有多个字节数据,ll区表示了它有多少个字节的数据;cc:表示本条记录的校验和,它是前面所有16进制数据 (除冒号外,两个为一组)的和对256取模运算的结果的补码。axf文件不仅包含代码数据,还包含了工程的各种信息,hex文件是一种使用十六进制符号表示的代码记录,记录了代码应该存储到FLASH的哪个地址,下载器可以根据这些信息辅助下载;bin文件是最直接的代码映像,它记录的内容就是要存储到FLASH的二进制数据(机器码本质上就是二进制数据),在FLASH中是什么形式它就是什么形式,没有任何辅助信息。
  46. map文件是由链接器生成的,它主要包含交叉链接信息,查看该文件可以了解工程中各种符号之间的引用以及整个工程的Code、RO-data、RW-data以及ZI-data的详细及汇总信息。它的内容中主要包含了“节区的跨文件引用”、“删除无用节区”、“符号映像表”、“存储器映像索引”以及“映像组件大小”。
  47. 当工程按默认配置构建时,MDK会根据我们选择的芯片型号,获知芯片的内部FLASH及内部SRAM存储器概况,生成一个以工程名命名的后缀为*.sct的分散加载文件(Linker Control File,scatter loading),链接器根据该文件的配置分配各个节区地址,生成分散加载代码,因此我们通过修改该文件可以定制具体节区的存储位置。利用它还可以控制代码的加载区与执行区的位置,例如可以把程序代码存储到单位容量价格便宜的NAND-FLASH中,但在NAND-FLASH中的代码是不能像内部FLASH的代码那样直接提供给内核运行的,这时可通过修改分散加载文件,把代码加载区设定为NAND-FLASH的程序位置,而程序的执行区设定为外部SRAM中的位置,这样链接器就会生成一个配套的分散加载代码,该代码会把NAND-FLASH中的代码加载到外部SRAM中,内核再从外部SRAM中运行主体代码,大部分运行Linux系统的代码都是这样加载的。sct文件中主要包含描述加载域及执行域的部分,一个文件中可包含有多个加载域,而一个加载域可由多个部分的执行域组成。sct文件具体语法见MDK章节ppt8(可以在sct文件中设置某个节区存储的位置,如名为EXRAM的节区,然后在代码中用形如int Extest[1024] __attribute__((section(“EXRAM”)))={0}的语法将变量存储到目标存储器)。
  48. 一般在MDK中编写工程应用后,调试时都是把程序下载到芯片的内部FLASH运行测试的,代码的CODE及RW-data的内容被写入到内部FLASH中存储。但在某些应用场合下却不希望或不能修改内部FLASH的内容,这时就可以使用RAM调试功能了,它的本质是把原来存储在内部FLASH的代码(CODE及RW-data的内容)改为存储到SRAM中(内部SRAM或外部SDRAM均可),芯片复位后从SRAM中加载代码并运行。CM-3内核在离开复位状态后的工作过程如下:从地址0x00000000处取出栈指针MSP的初始值,该值就是栈顶的地址;从地址0x00000004处取出程序指针PC的初始值,该值指向复位后应执行的第一条指令。虽然内核是固定访问0x00000000和0x00000004地址的,但实际上这两个地址可以被重映射到其它地址空间。以STM32F103为例,根据芯片引出的BOOT0及BOOT1引脚的电平情况,这两个地址可以被映射到内部FLASH、内部SRAM以及系统存储器中(系统存储器是一段特殊的空间,用户不能访问,ST公司在芯片出厂前就在系统存储器中固化了一段代码。因而使用系统存储器启动方式时,内核会执行该代码,该代码运行时,会为ISP提供支持(In System Program),如检测USART1/3、CAN2及USB通讯接口传输过来的信息,并根据这些信息更新自己内部FLASH的内容,达到升级产品应用程序的目的,因此这种启动方式也称为ISP启动方式。)。由启动文件startup_stm32f10x.s决定了0x00000000和0x00000004地址存储什么内容,链接时,由分散加载文件(sct)决定这些内容的绝对地址,即分配到内部FLASH还是内部SRAM(可参考在SRAM中调试代码章节相应ppt)。
  49. STM32的内部FLASH包含主存储器、系统存储器以及选项字节区域,一般说STM32内部FLASH的时候,都是指这个主存储器区域,指南者的FLASH(即主存储区域)大小为512KB。读写内部FLASH步骤(写选项字节区域也需要按照此步骤解锁后再写,但注意解锁用到的寄存器不同):1.解锁:由于内部FLASH空间主要存储的是应用程序,是非常关键的数据,为了防止误操作修改了这些内容,芯片复位后默认会结FLASH上锁,这个时候不允许设置FLASH的控制寄存器,并且不能对修改FLASH中的内容。所以对FLASH写入数据前,需要先给它解锁;2. 擦除扇区:在写入新的数据前,需要先擦除存储区域,STM32提供了扇区擦除指令和整个FLASH擦除(批量擦除)的指令,批量擦除指令仅针对主存储区;3. 写入数据:擦除完毕后即可写入数据,写入数据的过程并不是仅仅使用指针向地址赋值,赋值前还还需要配置一系列的寄存器(具体如何实现参考读写内部FLASH章节ppt2)。FLASH的读写保护及解除:修改选项字节的内容可修改读写保护配置,选项字节复位后的默认状态是始终可以读但被写保护的(具体读写规则设置参考设置FLASH读写保护及解除章节ppt1)。

Stm32F103外设使用方式总结:

  1. GPIO:相应时钟使能(如RCC_APB2PeriphClockCmd(GPIOB,ENABLE))->配置GPIO端口的模式(利用结构体GPIO_InitTypeDef设置输入还是输出,具体哪种输入输出)->按设置的结构体初始化GPIO(如GPIO_Init(GPIOB,&GPIO_InitStruct))。
  2. RCC系统时钟树设置:首先复位时钟寄存器(系统上电后默认配置成72M,修改前先用RCC_DeInit()复位)->使能外部晶振(RCC_HSEConfig(RCC_HSE_ON)当然也可以选择使用内部晶振,相关的固件库函数改成HSI对应函数即可)->判断是否使能成功(RCC_WaitForHSEStartUp())->若成功则继续设置FLASH预取指和取指间隔周期(FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable)和FLASH_SetLatency())->分别设置HCLK、PCLK1、PCLK2时钟(分别对应AHB、APB1和APB2,使用RCC_HCLKConfig()、RCC_PCLK1Config()、RCC_PCLK1Config()来设置)->设置锁相环时钟PLLCLK,将其使能并等待使能完成(可使用RCC_PLLConfig()、RCC_PLLCmd(ENABLE)、RCC_GetFlagStatus(RCC_FLAG_PLLRDY),在配置PLLCLK之前必须确保PLL处于disable状态,其默认状态为disable)->将系统时钟SYSCLK设置为PLLCLK并等待设置完成(RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK)、RCC_GetSYSCLKSource())。
  3. Stm32F103是基于Cortex-M3内核的,这个内核的核内外设NVIC将中断分为10个内部中断和60个外部中断,大部分中断可设置软件优先级,软件优先级相同时按照硬件优先级排序。stm对NVIC进行了裁剪,软件优先级用高四位来配置,包括主优先级和子优先级,共有五种分组情况。可通过NVIC_PriorityGroupConfig()函数对SCB->AIRC寄存器写入相应的值来设置优先级分组,在整个程序中只需要设置一次。以下为外部中断EXTI0的实现具体编程步骤(stm32F103共有19个EXTI中断类型,EXTI0-EXTI15对应16类GPIO口(PA-PE)):首先配置系统优先级分组情况,只需要配置一次(通过NVIC_PriorityGroupConfig()配置,这个函数在misc.c文件中定义)->设置要使用的中断类型,并设置该中断软件优先级,初始化NVIC(用NVIC_Init(&NVIC_InitStruct)初始化,初始化函数中包括了NVIC使能的操作,有些中断类型如EXTI9_5_IRQn对应多个外部中断)->初始化相关GPIO端口(如按键KEY1对应PA0口,用GPIO_Init(KEY1_INT_GPIO_PORT,&GPIO_InitStruct)初始化)->使能外设AFIO,并选择EXTI0对应的输入端口(输入线可为PA0、PB0、…、PE0,这里选择PA0,用函数RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE)使能AFIO,用GPIO_EXTILineConfig(GPIO_PORTSOURCE, GPIO_PIN)选择EXTI0输入端口,该函数在头文件stm32f10x_gpio.c中定义)->初始化EXTI,配置触发方式、模式等(EXTI_Init(&EXTI_InitStruct),初始化函数中包括了EXTI使能的操作)->在stm32f10x_it.c中编写相关中断服务函数(函数名必须和中断向量表一模一样)(中断挂起状态即中断被触发了)。
  4. Systick滴答时钟是Cortex-M3的核内外设,他产生的中断属于内部中断,使用方式为:用SysTick_Config()函数(这个函数在core_cm3.h中定义)初始化定时器,设置reload的值(在SysTick_Config()函数中可以看到内部中断的优先级需要使用函数NVIC_SetPriority ()来设定,NVIC的相关寄存器如ISR、IP等里面并没有记录内部中断的信息,只包含外部中断信息,内部中断优先级信息记录在内核的SCB_SHPRx寄存器中。内部中断和外部中断都是按照系统的优先级分类来判别优先级。)->根据SysTick->CTRL的值循环判断构建延时函数->在stm32f10x_it.c中编写相关中断服务函数,默认是空函数(函数名必须和中断向量表一模一样)。
  5. USART的使用步骤(5个串口的起始地址是不一样的,USART通信传送的是16进制数据或者ASCII码):使能USART的TX和RX引脚对应的GPIO(如GPIOA对应的时钟使能RCC_APB2PeriphClockCmd())->初始化对应的GPIO(GPIO_Init(),按照TX或RX设置成输出或输入模式)->对应的USART时钟使能->初始化相应的USART(USART_Init(),设置停止位、奇偶校验、字长等信息)->按需要使能接收、发送等中断(USART_ITConfig(),所有的中断都是进入USARTx_IRQHandler中断处理函数)->若使能了中断则需要配置中断优先级等信息(通过函数NVIC_PriorityGroupConfig()配置系统中断分组信息,使用函数NVIC_Init(&NVIC_InitStruct)初始化这类中断)->使能串口(USART_Cmd())->根据需要调用相关固件库函数实现数据发送和接收(如USART_SendData()、注意状态寄存器SR中一些标志位如TXE、TC等的使用)。
  6. 在stm32中,如果外设要想通过 DMA 来传输数据,必须先给 DMA 控制器发送 DMA 请求。DMA 有 DMA1 和 DMA2 两个控制器, DMA1 有 7 个通道, DMA2 有 5 个通道,不同的 DMA 控制器的通道对应着不同的外设请求。DMA可通过寄存器(DMA_CRRx->PL)设置软件优先级(0-4),软件优先级相同时DMA1优先级高于DMA2,同一个DMA中通道编号越小优先级越高。具体外设只能用其中某个DMA通道,M->M的DMA传输可以用任意通道。DMA的使用步骤:1>M->M(比如从FLASH到SRAM): 创建一个const类型的数组和一个同样大小的数组(const类型的数组存储在FLASH中,一般数组变量存储在SRAM中)->DMA时钟使能(RCC_AHBPeriphClockCmd())->初始化DMA,设置外设地址(这里为创建的const数组)和存储器地址(这里为创建的一般数组) ,设置传输方向,接收和发送的单位数据大小等信息(用DMA_Init()初始化,DMA数据传输过程中,若传输和接受的单个数据大小不一样,可参考手册具体怎么转换)->根据需要可以设置DMA中断并配置中断优先级等信息(DMA_ITConfig()和NVIC_Config())->清除DMA的传输完成标志位TC并使能DMA(用DMA_ClearFlag()清除,用DMA_Cmd()使能),数据开始传输。2>M->P(比如SRAM->USART):创建一个数组(该数组存储在SRAM中)->时钟使能GPIO和USART->配置USART的TX和RX引脚的输入输出模式,初始化USART(USART_Init())->根据需要设置串口中断-> DMA时钟使能(RCC_AHBPeriphClockCmd())->初始化DMA,设置外设地址(这里为对应的USART地址)和存储器地址(这里为创建的数组) ,设置传输方向,接收和发送的单位数据大小等信息(用DMA_Init()初始化)->根据需要可以设置DMA中断并配置中断优先级等信息(DMA_ITConfig()和NVIC_Config())->清除DMA的传输完成标志位TC并使能DMA(用DMA_ClearFlag()清除,用DMA_Cmd()使能)->开启USART的DMA数据发送使能(USART_DMACmd(USARTx, USART_DMAReq_Tx, ENABLE)),数据开始传输。
  7. stm32有两个I2C外设I2C1和I2C2,使用I2C时,对应的GPIO一般选择开漏输出(stm32的GPIO在输出模式时输入寄存器IDR中的值仍有效,即可以接收输入),IIC主模式硬件实现步骤:IIC时钟使能、对应GPIO时钟使能(如使能I2C1的函数为RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1),使能I2C1对应的GPIO的函数为RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB))->初始化GPIO和初始化I2C(一般GPIO选择开漏输出模式GPIO_Init(),I2C一般默认使能应答ACK,波特率一般为400KHZ,I2C自身的地址只要是总线上唯一的即可)->I2C使能(I2C_Cmd())->根据手册中I2C的主模式传送时序图,检测相关事件信号实现I2C和EEPROM之间的数据读写(板载的EEPROM为AT24C02,它的页面大小为8字节,在进行连续写操作时,如果写到页边界,会回到当前页的首地址继续写,而读操作可以跨页读取。并且每次写后要检测EEPROM是否写完才能读取,若利用页写入模式,只有当写满8个字节(一个页)时,才需要等待写入完成,而如果用单字节写入模式,每写一个字节都需要等待写完成。)。
  8. stm32有三个SPI外设SPI1、SPI2和SPI3,由于SPI片选线CS控制简单,所以一般采用软件方式实现,SPI外设在主模式下,时钟信号由主机产生,不发送数据则不会产生时钟信号,发送数据和接收数据同步进行,想接收数据就必须发送数据,在发送一个字节数据后可以通过判断RXNE是否为1来判断数据是否发送完成。SPI主模式通信步骤为:SPI时钟使能、对应GPIO时钟使能(如使能SPI1的函数为RCC_APB2PeriphClockCmd (RCC_APB2Periph_SPI1),使能SPI1对应的GPIO 函数为RCC_APB2PeriphClockCmd())->初始化SPI和对应的GPIO(一般选择二分频,则SPI1频率为36MHZ,选择软件控制CS线SPI_Init()、GPIO_Init())->拉高CS线并使能SPI(SPI_Cmd())->编写SPI读取和写入函数(SPI读写是同时进行的,可通过一个函数实现)->编写FLASH读写函数(FLASH写入前必须进行擦除操作,一般擦除扇区。写入数据后要等待FLASH内部写完才能读取,擦除操作也要等待。板载的FLASH为W25Q64,大小8MB,一次最多写入256个字节,如超过会在当前256字节中循环写入,这和型号为AT24C02的EEPROM类似)。
  9. FSCM扩展外部SRAM实现步骤:找到FSCM数据线、地址线、读写控制线等对应的GPIO,对这些GPIO时钟使能并初始化(RCC_APB2PeriphClockCmd()、GPIO_Init())->设置结构体FSMC_NORSRAMTimingInitTypeDef(设置地址建立时间、地址保持时间等参数,具体可根据外扩的SRAM的通信时序图设置,这里使用的是模式A)和FSMC_NORSRAMInitTypeDef(设置FSMC映射的存储区域、存储器数据宽度、是否使用扩展模式即读写是否使用相同的时序等参数,前一个结构体是这个结构体的成员)->初始化FSCM配置(FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure)),开启FSMC时钟->使能所使用的Bank即FSCM映射的存储区域(如FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM3, ENABLE))。使用 FSMC 外接存储器时,其存储单元是映射到 STM32 的内部寻址空间的,所以对FSCM扩展的存储区域直接通过地址就可以访问。C语言可以在定义变量时,可以通过形如int value __attribute__ ((at(DEFINE_ADDR)))的语法来直接指定所定义的变量所在内存位置,但定义的必须是全局变量才有效。具体见stm32参考手册。
  10. LCD液晶屏常用的8080时序的引脚有(指南者使用的3.2寸TFT液晶屏的内置液晶控制芯片是ILI9341,采用8080时序通信): LCD_CS片选信号、LCD_RD读使能、LCD_WR写使能、LCD_DC数据或者命令管脚(控制LCD_Data传输的是数据还是命令,一般是 1:数据读写,0:命令读写)、LCD_Data[X:0]X+1位的双向数据/命令总线。使用FSMC控制LCD步骤:根据指南者原理图中的液晶接口部分初始化各个GPIO并使能(RCC_APB2PeriphClockCmd()、GPIO_Init()。LCD_RST和LCD_BL采用普通推挽输出,其他均采用复用推挽输出)->设置结构体FSMC_NORSRAMTimingInitTypeDef(设置地址建立时间、地址保持时间等参数,这里使用的是模式B)和FSMC_NORSRAMInitTypeDef(设置FSMC映射的存储区域、存储器数据宽度、是否使用扩展模式即读写是否使用相同的时序等参数,前一个结构体是这个结构体的成员),开启FSMC时钟->初始化FSCM配置,将其配置为异步NOR FLASH模式以仿真8080时序(FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure))->使能所使用的Bank即FSCM映射的存储区域(如FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE))->初始化 ILI9341 寄存器,主要是配置了液晶屏的上电过程、显示屏的伽玛参数、分
  11. 辨率、像素格式等内容->设置显示区域相应坐标,设置扫描方向(0x2A命令设置x坐标,0x2B命令设置y坐标,ili9341液晶屏共有8种扫描示模式,即x、y不同扫描方向,从左到右,从上到下扫描等,一般用模式6)->如要显示字符则需构建字库(如果是英文ASCII码可以直接用数组写在程序中,如果是中文GB2312则需要存储在FLASH外设或者SD卡中,因为身体stm32的内部flash只有512K,大小不够),根据不同的字库用相应的公式计算不同字符的字模(对于GB2312要注意存储时的大小端问题)->根据液晶屏芯片手册向其显存写入或读取数据(填充像素命令为0x2C,液晶屏会根据写入字符对应的字模各个位的值显示相应的颜色)。(对于浮点数、整数等显示可以用sprintf函数将其转换为字符串再显示出来)
  12. 使用普通GPIO软件模拟SPI与触摸板通信步骤(指南者使用的触摸芯片是XPT2046):根据原理图初始化与触摸板SPI接口相连接的GPIO引脚(CS、MOSI、CLK对应的GPIO引脚设置为普通推挽输出,MISO、PENIRO对应的GPIO引脚设置为浮空输入)->编写触摸芯片的控制驱动,如发送命令字,获取触摸坐标等(发送命令0x90,即通道 Y+ 的选择控制字后可读取y坐标,发送命令0xd0,即通道 X+ 的选择控制字后可读取x坐标,这两个命令读到的ADC数值为12位的,也可用其他命令设置为8位)->编写触摸校正程序(可根据一般的触摸校准算法的数学关系把逻辑坐标与物理坐标转换公式的各个系数计算出来)->编写测试程序检验驱动(可使用触摸状态机,通过检测PENIRO电平来实现检测是否触摸电阻屏,还可以通过中断的方式实现,然后根据检测到的触摸点的坐标位置控制LCD做出相应的变换)。
  13. ADC通道分为规则通道和注入通道。单通道中断读取ADC输入模拟信号的步骤:初始化所使用的ADC外设通道对应的GPIO(指南者默认是PC1,需采用模拟输入模式)->初始化ADC初始化结构体(独立模式,单通道等)->配置ADC时钟频率(如8分频:RCC_ADCCLKConfig(RCC_PCLK2_Div8))->配置ADC通道转换顺序和采样时间(ADC_RegularChannelConfig())->使能ADC中断(ADC_ITConfig(ADCx, ADC_IT_EOC, ENABLE))->使能ADC(ADC_Cmd(ADCx, ENABLE)开始转换)->校准ADC(ADC_ResetCalibration(ADCx)、 ADC_StartCalibration(ADCx)这两个函数执行需要时间,需要用while循环等待一下)->采用软件触发ADC,真正开始转换(ADC_SoftwareStartConvCmd(ADCx, ENABLE))->编写相应的中断服务函数(ADC_NVIC_Config())。单通道DMA读取时(只使用一个ADC)将DMA传输的外设地址设为ADC对应的数据寄存器ADCx->DR即可,存储器地址可取一个全局变量的地址(注意要是能DMA请求ADC_DMACmd(ADCx, ENABLE),ADC2不具有DMA功能,使用DMA传输时只能使用ADC1或ADC3)。多通道DMA读取(只使用一个ADC)与单通道DMA读取类似,只是初始化时应将存储器地址取为一个数组(数组大小为要读取的通道数),存储器地址改为每次读完增加,外设地址仍设为ADC对应的数据寄存器ADCx->DR,配置ADC 通道的转换顺序和采样时间时,每个通道都需要配置。双ADC规则模式(指南者只能同时使用ADC1和ADC2)下,ADC2读取的数据会存储到ADC1数据寄存器DR的高16位中,然后可以借助ADC1的DMA功能将读取的数据传输到数组中(即SRAM中),这个模式下ADC1和ADC2读取的通道数必须相同而且不能在同一个时间段内读取同一个通道,ADC1设置为软件触发方式,ADC2设置为外部触发方式。
  14. 指南者的定时器分为基本定时器、通用定时器和高级定时器,TIM6、TIM7是基本定时器,没有外部GPIO,只能用来定时,只能向上计数。三种定时器的计数器都是16位,频率72Hz。基本定时器的各计数器的时钟频率CK_CNT等于fCK_PSC/(PSC[15:0]+1)(其中fCK_PSC为72Hz,PSC为预分频寄存器中的值),自动重装载寄存器ARR控制计数次数(实际所用周期为ARR寄存器的值加1)。基本寄存器使用步骤:初始化基本定时器结构体,并使能定时器(需要开启计数器中断)->设置相应的中断服务函数。
  15. SD卡:标准库函数对 SDIO 外设建立了三个初始化结构体,分别为 SDIO 初始化结构体 SDIO_InitTypeDef、SDIO 命令初始化结构体 SDIO_CmdInitTypeDef 和 SDIO 数据初始化结构体 SDIO_DataInitTypeDef。SD 卡驱动程编写步骤为:初始化相关 GPIO 及 SDIO 外设(参考指南者原理图)->配置 SDIO 基本通信环境进入卡识别模式,通过几个命令处理后得到卡类型->如果是可用卡就进入数据传输模式,接下来就可以进行读、写、擦除的操作。在SD卡中移植FatFs文件系统时,需要注意的地方是SD卡数据操作是使用DMA传输的,并设置数据尺寸为32位大小,为实现数据正确传输,要求存储区是4字节对齐。在某些情况下,FatFs 提供的buff地址不是4字节对齐,这会导致DMA数据传输失败(具体解决方法参考野火开发指南第36章)。
  16. CAN通讯实现步骤(指南者没有CAN收发器,所以只能用回环模式进行测试,以下步骤为采用中断处理方式):初始化与CAN相关的GPIO(若使用的是重定义的GPIO引脚,则需要修改AFIO_MAPR寄存器的CAN_REMAP位,GPIO_PinRemapConfig (GPIO_Remap1_CAN1 ,ENABLE);还要开启AFIO的时钟,RCC_APB2PeriphClockCmd (RCC_APB2Periph_AFIO, ENABLE );)->初始化CAN(使用CAN_InitTypeDef结构体设置波特率、回环模式等参数,然后CAN_Init(CAN1,&CAN_InitTypeStruct);)->配置CAN的过滤器(使用CAN_FilterInitTypeDef结构体设置相关参数,然后使用函数CAN_ITConfig (CAN1,CAN_IT_FMP0,ENABLE);配置)->设置CAN接收中断(CAN_NVIC_Config())->在中断处理函数中接收数据。
  17. 在SRAM中调试代码具体步骤:在原工程的基础上创建一个调试版本(保护原工程不被破坏)->修改分散加载文件(.sct文件)->添加宏定义修改STM32的中断向量表地址->修改仿真器和下载器配置,使程序能通过下载器存储到内部SRAM->将BOOT0与BOOT1均接上高电平(原本BOOT0接的地,即默认为从内部FLASH启动,现在该位从内部SRAM启动,但是指南者硬件存在bug,可改为添加仿真器命令脚本文件 *.ini解决)->尝试给 SRAM 下载程序或仿真调试(可参考野火开发指南第44章)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值