【STM32笔记】 基础调试篇
- 格式:doc
- 大小:25.50 KB
- 文档页数:3
STM32学习笔记:读写内部Flash(介绍+附代码)⼀、介绍⾸先我们需要了解⼀个内存映射:stm32的flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯⽚实际的flash⼤⼩,不同的芯⽚flash⼤⼩不同。
RAM起始地址是0x2000 0000,结束地址是0x2000 0000加上芯⽚的RAM⼤⼩。
不同的芯⽚RAM也不同。
Flash中的内容⼀般⽤来存储代码和⼀些定义为const的数据,断电不丢失,RAM可以理解为内存,⽤来存储代码运⾏时的数据,变量等等。
掉电数据丢失。
STM32将外设等都映射为地址的形式,对地址的操作就是对外设的操作。
stm32的外设地址从0x4000 0000开始,可以看到在库⽂件中,是通过基于0x4000 0000地址的偏移量来操作寄存器以及外设的。
⼀般情况下,程序⽂件是从 0x0800 0000 地址写⼊,这个是STM32开始执⾏的地⽅,0x0800 0004是STM32的中断向量表的起始地址。
在使⽤keil进⾏编写程序时,其编程地址的设置⼀般是这样的:程序的写⼊地址从0x08000000(数好零的个数)开始的,其⼤⼩为0x80000也就是512K的空间,换句话说就是告诉编译器flash的空间是从0x08000000-0x08080000,RAM的地址从0x20000000开始,⼤⼩为0x10000也就是64K的RAM。
这与STM32的内存地址映射关系是对应的。
M3复位后,从0x08000004取出复位中断的地址,并且跳转到复位中断程序,中断执⾏完之后会跳到我们的main函数,main函数⾥边⼀般是⼀个死循环,进去后就不会再退出,当有中断发⽣的时候,M3将PC指针强制跳转回中断向量表,然后根据中断源进⼊对应的中断函数,执⾏完中断函数之后,再次返回main函数中。
⼤致的流程就是这样。
1.1、内部Flash的构成:STM32F429 的内部 FLASH 包含主存储器、系统存储器、 OTP 区域以及选项字节区域,它们的地址分布及⼤⼩如下:STM32F103的中容量内部 FLASH 包含主存储器、系统存储器、 OTP 区域以及选项字节区域,它们的地址分布及⼤⼩如下:注意STM32F105VC的是有64K或128页x2K=256k字节的内置闪存存储器,⽤于存放程序和数据。
/******************************************************************* 文件名:书写程序中一些特别需要留意的地方文件编辑人:张恒编辑日期:15/11/23功能:快速查阅巩固知识点*******************************************************************/ 版本说明:v1.0版本:1.开始编辑书写整个文档,开始用的为TXT文档的形式,整理了部分学习到的东西和一些在书写常用程序中容易出错的地方,以及经常忽视细节而导致程序运行失败,是巩固知识点,提醒值得注意地方的工具文档。
2.添加的功能上基本涵盖了所有的模块,除了串口通信中的SPI和I2C、I2S等,应用是比较简单后续可能会添加。
3.对一些特定的功能综合应用并未加入进去,这是一个不好的地方,后续应该会随着学习总结更新,每次更新记录为一个版本。
// 2015/11/24;v1.1版本:1.将所有的TXT版本的文档全部转换为DOC模式,并且更新的加入了目录显示,显示为1级目录,方便查阅相关内容。
2.更新了SysTick书写中值得注意的地方3.更新了FSMC的一些细微操作,后续继续追捕更新书写细节。
V1.2版本:1.更新了FSMC部分功能显示,详细了FSMC的使用注意事项2.添加了RTC实时时钟的一些注意事项。
//2015/12/1;V1.3版本:1.更新RTC部分注意事项。
//2015/12/11V1.4版本:1.更新ADC校准标志部分注意事项。
2.更新了TIM1和TIM8的高级定时器特殊功能说明。
//2015/12/13V1.5版本:1.优化了部分注意事项,SysTick的写法上重新的定制写法。
2.优化了ADC在使用过程的一些细节注意地方。
3.面对最近出现的浮点数运算错误,配合AD数据进行总结。
4.RTC细节的把握-配置正确顺序的错误。
STM32F10x系列USB初学调试——by xiaohuolong1827关于STM32F10x系列USB调试,网上各大神已进行了相关详解,现对整体流程进行大概梳理。
1. 官方例程下载从ST官网下载USB示例程序,《STM32_USB-FS-Device_Lib_V4.1.0》,资源包编号“en.stsw-stm32121”。
有如下示例工程:2. 辅助工具/资料下载为了后续能愉快的调试示例程序,观察试验现象,可根据需要额外下载如下工具/资料:(1)Bus Hound。
此工具可以看到电脑上所有的device,并且选则相应的device时,点击capture,可以进行设备通信数据的捕获。
(2)单片机多功能调试助手-温子祺。
该助手具备查找USB设备功能(同时其他的功能也基本上是嵌入式开发者的必备工具。
)(3)HID调试助手。
进行USB设备的数据收、发。
(4)ST官网的HIDDemo_V1.0.2_Setup.exe工具(资源包编号en.stsw-stm32084)。
该工具是与Custom_HID示例程序配套的。
(5)ST官网的DfuSe_Demo_V3.0.6_Setup.exe工具(资源包编号en.stsw-stm32080)。
该工具是与DeviceFirmwareUpgrade示例程序配套的。
(6)USB官网的HID Descriptor Tool(我下载的是dt2_4.zip版本)。
该工具可用来辅助生产HID设备的描述符。
(7)USB基本协议,可参考网友的《STM32-USB学习笔记》、网友的《STM32 USB HID详解》、USB设备类别码、HID描述《Device Class Definition for Human Interface Devices (HID)》。
建议先读一下《STM32-USB学习笔记》。
3. 目标板从官方的文件包里来看,示例程序包含如下开发板:如果你没有上述开发板,也没有关系,只要你的试验板是上述型号的CPU并且引出了相关USB接口,就可以进行USB调试了(我就没有)。
AN2604应用笔记STM32F101xx and STM32F103xx RTC校准总体介绍实时时钟在很多嵌入式应用中是必不可少的,但是由于外部环境温度的改变,驱动RTC的晶体频率会发生变化,因此RTC就没有预想的那么准确了!STM32F101xx and STM32F103xx附带有数字时钟校准电路,因此可以适应与变化的环境,它主要是来补偿晶体由于环境的变化,这篇应用笔记主要讨论了RTC校准的基本原理以及解释了如何利用RTC校准来提高计时精度。
1RTC校准基本原理1.1晶体的准确性在很多计时领域,通常都是用“石英精确度”这么一个术语来描述的,石英晶体振荡器提供了一个远远优于其他类型振荡器的精确度,但是它并不是完美的,石英晶体振荡器对温度十分敏感,Figure1展示了一个32.768HZ晶体的频率精确度(acc)和温度(T)以及曲率(K)的关系,这个曲线可以用下面的公式给出:注:曲率K由于不同的晶体而不同,这里是针对STM3210B-EVAL开发板来说的,关于这部分可以参考相关晶体制造商提供的详细信息。
在很多应用领域需要一个高准确度的时钟,但是在实际中有好多综合因素限制着精度的提高,通常,典型的方法是通过调节晶体的负载电容来调节精度,这一方法,虽然十分有效,但是也存在这一些缺点:1它需要多加一个外部器件(可调电容)。
2其增大了电流消耗(这在电池供电的场合尤为突出)。
取代这种传统的模拟的方法,STM32F10xxx系列提供了一个数字校准器,允许用户用软件控制的方法进行校准,非常的好用!1.2具体方法STM32F10xxx的RTC模块是用一个32768HZ的通常石英晶体驱动的,其实石英晶体是一种能够提供非常固定频率的,但是有以下两种情况导致了其频率的不稳定:1温度变化;2晶体本身的变化。
前面讲述了一般通常的方法都是用一个麻烦的可调电容来补偿误差,这里STM32F10xxx使用的是一个周期计数器来进行校正,这个数字校正器通过从220个时钟周期中减去0到127个周期的方法来校正的,如图所示:究竟有多少个时钟节拍是空白的取决于最近一次向备份寄存区域RTC校准寄存器最后七位加载的值,之所以这个校准寄存器放在备份区域是因为这个寄存器即使在系统掉电情况下仍然可以通过后备电池进行供电(译者注:如果后背电池也掉电,当然这个寄存器的值也会丢失的),注意:从上图中可以看出时钟输出引脚是在校准之前的频率,所以这个值是不会被校准所改变的,尽管已经进行了校准,但是这个输出是在校准之前的频率。
STM32自学笔记作者:忙碌的小姚新浪微博:@忙碌的小姚新浪博客:/mlxiaoyao222目录STM32 自学笔记 (1)第一章 (3)我与STM32 的那些日子 (3)第二章 (4)使用固件库建立一个工程 (4)1、了解STM32F103的固件库 (4)2、创建第一个工程 (4)3、接下来就是管理工程文件了 (9)4、编写main.c 和文件路径 (10)第三章 (14)STM32点亮第一个LED 使用keil for ARM MDK 软件仿真 (14)1、Main.c 函数代码: (14)2、代码分析: (15)3、软件仿真介绍: (16)第四章 (19)串口的使用 (19)1、为什么要用串口? (19)2、STM32跟PC机(也就是电脑)如何连接 (19)3、代码分析 (20)4、仿真及调试 (23)5、串口接收数据 (25)第五章 (27)通用定时器的使用 (27)1、STM32F103内部定时器有哪些? (27)2、如何进行程序编写 (27)3仿真结果观察 (30)4对第四章串口的补充 (31)5工程代码 (35)第一章我与STM32 的那些日子STM32这块板子是在阿莫上跟一个老师买的,砍了半天100块钱。
包括一个Jlink v8仿真器(好像65块左右),和一块STM32系统板。
那已是一年前的事了。
那时我刚大三,刚学了半年51,于是想学点更高级的。
但我好像属于三分钟热度的这种人,买回来学了一个星期,就学不动了,寄存器操作,固件库的使用根本就没明白是怎么一回事,之后就没有然后了。
现在看到那块板子,总有一种说不出的滋味,要是当时能咬牙切齿努力学习,说不定现在也不会安静地坐在电脑前一字一句敲打这篇激励性文章了。
对于STM32我没用任何基础,唯一有的也只是一年前学的那一个星期,不过那已不重要了,我现在仍是一个小白。
作为一个初学者,也许是坐井观天,看的是片面的,可能有很多观点是错误的,希望读者朋友能勇于指出来。
推挽输出与开漏输出的区别推挽输出推挽输出::可以输出高可以输出高,,低电平低电平,,连接数字器件连接数字器件; ;开漏输出开漏输出::输出端相当于三极管的集电极输出端相当于三极管的集电极. . 要得到高电平状态需要上拉电阻才行要得到高电平状态需要上拉电阻才行. . 适合于做电流型的驱动电流型的驱动,,其吸收电流的能力相对强其吸收电流的能力相对强((一般20ma 以内以内). ).推挽结构一般是指两个三极管分别受两互补信号的控制推挽结构一般是指两个三极管分别受两互补信号的控制,,总是在一个三极管导通的时候另一个截止另一个截止. .要实现“线与”需要用OC(open collector)collector)门电路门电路门电路..是两个参数相同的三极管或MOSFET,以推挽方式存在于电路中以推挽方式存在于电路中,,各负责正负半周的波形放大任务各负责正负半周的波形放大任务,,电路工作时,两只对称的功率开关管每次只有一个导通,所以导通损耗小关管每次只有一个导通,所以导通损耗小,,效率高。
输出既可以向负载灌电流,也可以从负载抽取电流。
抽取电流。
问题:问题:很多芯片的供电电压不一样,有3.3v 和5.0v 5.0v,需要把几种,需要把几种IC 的不同口连接在一起,是不是直接连接就可以了?实际上系统是应用在I2C 上面。
上面。
简答:简答:1、部分3.3V 器件有5V 兼容性,可以利用这种容性直接连接兼容性,可以利用这种容性直接连接2、应用电压转换器件,如TPS76733就是5V 输入,转换成3.3V 3.3V、、1A 输出。
输出。
开漏电路特点及应用在电路设计时我们常常遇到开漏(在电路设计时我们常常遇到开漏(open drain open drain )和开集()和开集()和开集(open collector open collector )的概念。
所)的概念。
所谓开漏电路概念中提到的“漏”就是指MOSFET 的漏极。
STM32学习笔记——之USART2篇USART2位于APB1总线学习环境:STM32芯片:STM32F103VBT6开发板:万利STM3210B-LK1USART2引脚PD5——USART2 TX,PD6——USART2 RX (重定义引脚)1、USART2与PC通信(USART2发送)首先需要对USART2配置,因为在万利板子上的USART2进行了重映射,因此配置跟USART1有区别①开启GPIOD以及AFIO时钟,开启USART2时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //USART2在APB1总线②配置USART2的TX(PD5)以及RX(PD6)引脚先进行定义结构体变量,用来配置相应引脚的速度以及输入输出模式GPIO_InitTypeDef GPIO_InitStructure;进行USART2的重映射配置GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE); //USART2重映射配置USART2的RX(PD6)引脚GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入GPIO_Init(GPIOD, &GPIO_InitStructure);配置USART2的TX(PD5)引脚GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出GPIO_Init(GPIOD, &GPIO_InitStructure);③配置USART1的波特率、数据位数、停止位、校验以及硬件流控制首先定义结构体变量USART_InitTypeDef USART_InitStructure;USART_ART_BaudRate = 9600; //波特率--9600USART_ART_WordLength = USART_WordLength_8b; //数据位数--8位USART_ART_StopBits = USART_StopBits_1; //停止位—1位USART_ART_Parity = USART_Parity_No; //无校验USART_ART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流控制USART_ART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_Init(USART1, &USART_InitStructure);④使能USART1USART_Cmd(USART1, ENABLE);通过上面四个步骤的操作,即可完成对USART2的配置。
SYS.C程序解释#i nclude <stm32f10x_lib.h>#include "sys.h"//设置向量表偏移地址〃NVIC_VectTab:基址//Offset: 偏移量//CHECK OK//091207void MY_NVIC_SetVectorTable(u32 NVIC_VectTab, u32 Offset){//检查参数合法性assert_param(IS_NVIC_VECTTAB(NVIC_VectTab));assert_param(IS_NVIC_OFFSET(Offset));SCB->VTOR = NVIC_VectTab|(Offset & (u32)0x1FFFFF80); // 设置NVIC 的向量表偏移寄存器//用于标识向量表是在COD区还是在RAM区}解释:前面两行是用来检查参数合法性,这里不作分析。
重点看第三行。
#defi ne NVIC_VectTab_RAM ((u32)0x)#defi ne NVIC_VectTab_FLASH @32)0x08000000)typedef struct{vuc32 CPUID; vu32 ICSR;vu32 VTOR; vu32 AIRCR;vu32 SCR;vu32 CCR;vu32 SHPR[3]; vu32 SHCSR;vu32 CFSR;vu32 HFSR;vu32 DFSR;vu32 MMFAR;vu32 BFAR; vu32 AFSR;} SCB_TypeDef;在VV权威指南>> 第一百零四页,有这么一段话:NVIC中有一个寄存器,称为向量表偏移量寄存器”在地址0xE000_ED08处),通过修改它的值就能定位向量表。
但必须注意的是:向量表的起始地址是有要求的:必须先求出系统中共有多少个向量,再把这个数字向上增大到是2的整次幕,而起始地址必须对齐到后者的边界上。
开始看STM32 好几天了看东西有个不太好的习惯总想看全全弄明白了再调其实这样是很不好滴浪费时间芯片在重新初始化时是会把设备配置成最小系统的当面对一个复杂的系统时(其实STM32datasheet有的地方写的不太好有点复杂个人感觉) 可以先抛开不使用的功能待日后再慢慢加上会是一个很愉快的过程
使用ST的固件库先用熟悉了再根据自己的习惯修改代码毕竟ST的CODER应该还是比较合理的吧
以下是几个需要用户修改的配置文件
stm32f10x_it.c
用户中断函数
stm32f10x_lib.h
用户程序唯一需要#include 的头文件
stm32f10x_conf.h
配置外围设备地址将相应的设备define 屏蔽掉后设备地址将不被编译程序用到会报错
其实主要的区别就是在初始化的方式上 STM32F103x有两个位带区分别为RAM 和PERHIAL即0x2000000 , 0x4000000开始的1M字节可以分别映射到
0x22000000 , 0x42000000开始的线性空间里,然后它们就可以位寻址了,就好像常用的单片机一样。
计算公式如下:
#define RAM_BASE 0x20000000
#define RAM_BB_BASE 0x22000000
#define Var_ResetBit_BB(VarAddr, BitNumber) \
(*(vu32 *) (RAM_BB_BASE | ((VarAddr - RAM_BASE) << 5) | ((BitNumber) << 2)) = 0)
#define Var_SetBit_BB(VarAddr, BitNumber) \
(*(vu32 *) (RAM_BB_BASE | ((VarAddr - RAM_BASE) << 5) | ((BitNumber) << 2)) = 1)
#define Var_GetBit_BB(VarAddr, BitNumber) \
(*(vu32 *) (RAM_BB_BASE | ((VarAddr - RAM_BASE) << 5) | ((BitNumber) << 2)))
以上是ST库里的宏直接用就好了同理定义好PERHIAL_BASE ,
PERHIAL_BB_BASE即可一样操作外围设备通过这种方法脱离ST的库结构许多
写法效率要高好多倍但如果不是硬用8位机算乘除法这样的极端例子跟自己死磕在ST PLL (1-16)*HES(high extern speed clock)的时钟下都没有太大的意义用库就好了不允许超过72MHz
所有的外围端口时钟都是独立的为了低功耗所以记得使用前打开相应设备的时钟这是第一步如:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOF | RCC_APB2Periph_USART1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4 | RCC_APB1Periph_TIM2 , ENABLE);
库的外围设备时钟初始化
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOF , &GPIO_InitStructure);
以GPIO来说初始化的顺序是先在变量结构里配置然后一次性写入所有库函数都有详细说明参数配置说明很好用既然用库就最好使用关联编辑器(source in sight)
一个通用定时器配置例子:
TIM_InternalClockConfig(TIM2);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM2_InitStruct.TIM_ClockDivision = TIM_CKD_DIV4;
TIM2_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM2_InitStruct.TIM_Period = (u16)0x2710;
TIM2_InitStruct.TIM_Prescaler = (u16)0x0708;
TIM2_InitStruct.TIM_RepetitionCounter = 0; //PWM 比较寄存器更新速率TIM_TimeBaseInit(TIM2 , &TIM2_InitStruct);
TIM_ClearFlag(TIM2, TIM_FLAG_Update); //这里是自己清的记得进中断清跑飞以后以为是初始化向量不对在那乱找
TIM_Cmd(TIM2, ENABLE);
相应中断配置
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //4 //4 bit
NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQChannel;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; //关于抢占中断响应中断外面有写
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
KEIL MDK #define __nop() nop() 两个"_" ......。