STM32笔记
- 格式:docx
- 大小:92.87 KB
- 文档页数:5
《STM32Cube高效开发教程》读书笔记目录一、前言 (2)1.1 书籍简介 (3)1.2 编写目的 (4)二、STM32Cube概述 (5)2.1 STM32Cube的意义 (6)2.2 STM32Cube的主要特点 (7)三、安装与配置 (9)3.1 STM32Cube的安装 (10)3.2 开发环境的配置 (11)四、创建项目 (12)4.1 新建项目 (13)4.2 项目设置 (14)五、HAL库介绍 (15)5.1 HAL库简介 (16)5.2 HAL库的主要组件 (18)六、STM32最小系统 (19)6.1 STM32最小系统的组成 (21)6.2 STM32最小系统的应用 (22)七、GPIO操作 (24)7.1 GPIO的基本概念 (25)7.2 GPIO的操作方法 (26)八、中断系统 (28)8.1 中断的基本概念 (29)8.2 中断的处理过程 (31)九、定时器 (33)9.1 定时器的功能介绍 (34)9.2 定时器的操作方法 (36)十五、文件系统 (37)一、前言随着科技的飞速发展,嵌入式系统已广泛应用于我们生活的方方面面,从智能手机到自动驾驶汽车,其重要性不言而喻。
而STM32作为一款广泛应用的微控制器系列,以其高性能、低功耗和丰富的外设资源赢得了广大开发者的青睐。
为了帮助开发者更好地掌握STM32系列微控制器的开发技巧,提升开发效率,我们特别推出了《STM32Cube 高效开发教程》。
本书以STM32Cube为核心,通过生动的实例和详细的讲解,全面介绍了STM32系列微控制器的开发过程。
无论是初学者还是有一定基础的开发者,都能从中找到适合自己的学习内容。
通过本书的学习,读者将能够更加深入地理解STM32的内部结构和工作原理,掌握其编程方法和调试技巧,从而更加高效地进行嵌入式系统的开发和应用。
在科技日新月异的今天,STM32系列微控制器将继续扮演着举足轻重的角色。
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字节的内置闪存存储器,⽤于存放程序和数据。
stm32学习经历(5篇可选)第一篇:stm32学习经历随便写写,关于stm32 最近在学习stm32,写点东西,虽然简单,但都是原创啊开发板是前辈画的,好像是用来测试一个3G功能的,不过对于我来说太远;我要来了3个,自己焊了一个最小系统,好在公司资源还是不错的,器件芯片有,还可以问问前辈--对公司还是比较满意的,虽然工资少了点,但学东西第一位O(∩_∩)O~。
最开始当然是建工程了,这个真不太会,前前后后竟用了一周(时间真长,别见笑啊),上网查资料,问前辈,自己琢磨。
总算搞定,然后从GPIO开始学,开始还真没什么头绪(虽然在大学学点51,但完全没有真正应用,顶多是跑马灯实验),开始纠结是从寄存器开始学还是从库函数开始学,后来看到一句“用库函数入门,用寄存器提高”于是下定决心用库,但当时没有库的概念,结果走了很多弯路,看了很多不必要的东西,当时竟没理解到只是调用库就OK了,别的不用管。
最后潜心的在教程网看完一个例程后照猫画虎写了一个,经过了多次调试以后,灯终于亮了!那个兴奋啊。
再次还要感谢希望自己坚持下去,早日能写出一个属于自己的程序,完成一个说的过去的功能,下面把我的程序粘出来,和大家分享下,大虾看到了别见笑啊注:1.有两个灯,PA4 B12,都是低电平点亮2.有两个按键,PB8 和 PB9,按下是低电平3.程序开始后两个灯常亮,按下按键后熄灭,抬起后继续亮main.c中#include "stm32f10x.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" #include "stm32f10x_exti.h" void RCC_Configuration(void) //时钟配置函数{ ErrorStatus HSEStartUpStatus; //使能外部晶振RCC_HSEConfig(RCC_HSE_ON); //等待外部晶振稳定HSEStartUpStatus = RCC_WaitForHSEStartUp(); //如果外部晶振启动成功,则进行下一步操作if(HSEStartUpStatus==SUCCESS) { //设置HCLK(AHB时钟)=SYSCLK 将系统时钟进行分频后,作为AHB总线时钟RCC_HCLKConfig(RCC_SYSCLK_Div1); //PCLK1(APB1) = HCLK/2 将HCLK时钟2分频后给低速外部总线RCC_PCLK1Config(RCC_HCLK_Div2); //PCLK2(APB2) = HCLK HCLK时钟配置给高速外部总线 RCC_PCLK2Config(RCC_HCLK_Div1); //外部高速时钟HSE 4倍频RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_4); //启动PLL RCC_PLLCmd(ENABLE); //等待PLL稳定while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //系统时钟SYSCLK来自PLL输出RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //切换时钟后等待系统时钟稳定 while(RCC_GetSYSCLKSource()!=0x08); } // 下面这些都是外设总线上所挂的外部设备时钟的配置RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_AP B2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE); }void GPIO_Configuration(void) //GPIO配置函数{ //GPIO_DeInit(GPIOA); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP; GPIO_Init(GPIOA,&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP; GPIO_Init(GPIOB,&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8|GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IPU;GPIO_Init(GPIOB,&GPIO_InitStructure); } void EXTI_Config(void) { EXTI_InitTypeDef EXTI_InitStructure; // 管脚选择GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource8);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource9); // 清除 EXTI线路挂起位EXTI_ClearITPendingBit(EXTI_Line8|EXTI_Line9); // EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_Line = EXTI_Line8|EXTI_Line9; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); } void NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; // 注意名称是“_IRQn”,不是“_IRQChannel”NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } int main(void) { RCC_Configuration(); GPIO_Configuration(); EXTI_Config(); NVIC_Config();while(1) { GPIO_ResetBits(GPIOB,GPIO_Pin_12); GPIO_ResetBits(GPIOA,GPIO_Pin_4); } } 中断文件 it.c中void EXTI9_5_IRQHandler(void) { if ( EXTI_GetITStatus(EXTI_Line8) != RESET ) { EXTI_ClearITPendingBit(EXTI_Line8);GPIO_SetBits(GPIOA,GPIO_Pin_4);while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8)==0); } if ( EXTI_GetITStatus(EXTI_Line9) != RESET ){ EXTI_ClearITPendingBit(EXTI_Line9);GPIO_SetBits(GPIOB,GPIO_Pin_12);while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)==0);勤劳的蜜蜂有糖吃} }第二篇:STM32入门经历,高手不要进!现在STM32初学入门,写些关于入门的帮助,也算答谢帮助过我的人.希望象我这样想学STM32的朋友不用迷茫.(本入门只适合低手,高手不要见笑).1.硬件平台.现在可以买到学习有的有英蓓特的MCBSTM32 和万利的EK-STM32F,可能目前出来最好的还是的神舟系列开发板,包括神舟I号(103RBT),神舟II号(103VCT),神舟III号(103ZET),神舟iv号(107VCT)几款都有,反正这几个板我都买了,学校出钱买的,还挺实惠,让老板打了个折扣,如果你自己开板做,成本还比这高.学会了才自己做自己的板子吧.2.软件平台.现在流行的有Keil MDK 3.15b和 IAR EWARM 4.42A. 购买评估板时,里面的光盘已经带了.为什么选这两个平台,用的人多,你以后遇到问题,可以找人解决的机会就大.英蓓特的MCBSTM32用的是Keil MDK 平台, 万利的是 IAR EWARM.3.C语言知识如果想补这推荐一本入门的书C Primer Plus 中文版.这本也是入门的好书.4.ST的数据手册STM32F10x参考手册看完这个就对STM32的内部有认识.STM32 Document and library rules 个人认为这个最重要.因为你学会了C语言看例程时.很多如GPIO_SetBits GPIO_ResetBits.很多C语言以外的函数库.这些都是STM32的库文件.5.看例程.如keil MDK 3.15b下的C:/Keil/ARM/Boards/Keil/MCBSTM32 有很多例程.GPIO口,RTC,PWM,USB,CAN等等....你想到的都有例程.6.多上论坛,呵呵.....有不明问下高手,我也是这样.只要不断努力,你一定会成功的.第三篇:STM32学习心得笔记STM32学习心得笔记时钟篇在STM32中,有五个时钟源,为HSI、HSE、LSI、LSE、PLL。
STM32⾃学笔记⼀、原⼦位操作:原⼦位操作定义在⽂件中。
令⼈感到奇怪的是位操作函数是对普通的内存地址进⾏操作的。
原⼦位操作在多数情况下是对⼀个字长的内存访问,因⽽位号该位于0-31之间(在64位机器上是0-63之间),但是对位号的范围没有限制。
原⼦操作中的位操作部分函数如下:void set_bit(int nr, void *addr)原⼦设置addr所指的第nr位void clear_bit(int nr, void *addr)原⼦的清空所指对象的第nr位void change_bit(nr, void *addr)原⼦的翻转addr所指的第nr位int test_bit(nr, void *addr)原⼦的返回addr位所指对象nr位inttest_and_set_bit(nr, void *addr)原⼦设置addr所指对象的第nr位,并返回原先的值int test_and_clear_bit(nr, void *addr)原⼦清空addr所指对象的第nr位,并返回原先的值int test_and_change_bit(nr, void *addr)原⼦翻转addr所指对象的第nr位,并返回原先的值unsigned long word = 0;set_bit(0, &word); /*第0位被设置*/set_bit(1, &word); /*第1位被设置*/clear_bit(1, &word); /*第1位被清空*/change_bit(0, &word); /*翻转第0位*/⼆、STM32的GPIO锁定:三、中断挂起:因为某种原因,中断不能马上执⾏,所以“挂起”等待。
⽐如有⾼、低级别的中断同时发⽣,就挂起低级别中断,等⾼级别中断程序执⾏完,在执⾏低级别中断。
四、固⽂件:固件(Firmware)就是写⼊EROM(可擦写只读存储器)或EEPROM(电可擦可编程只读存储器)中的程序。
/******************************************************************* 文件名:书写程序中一些特别需要留意的地方文件编辑人:张恒编辑日期: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细节的把握-配置正确顺序的错误。
STM32F103 系列芯片的系统架构:系统结构:在每一次复位以后,所有除SRAM 和FLITF 以外的外设都被关闭,在使用一个外设之前,必须设置寄存器RCC_AHBENR 来打开该外设的时钟。
GPIO 输入输出,外部中断,定时器,串口。
理解了这四个外设,基本就入门了一款MCU。
时钟控制RCC:-4~16M 的外部高速晶振-内部8MHz 的高速RC 振荡器-内部40KHz低速RC 振荡器,看门狗时钟-内部锁相环(PLL,倍频),一般系统时钟都是外部或者内部高速时钟经过PLL 倍频后得到- 外部低速32.768K 的晶振,主要做RTC 时钟源ARM存储器映像:数据字节以小端格式存放在存储器中。
一个字里的最低地址字节被认为是该字的最低有效字节,而最高地址字节是最高有效字节。
存储器映像与寄存器映射:ARM 存储器映像4GB0X0000 00000X1FFF FFFF0X2000 00000X3FFF FFFF0X4000 00000X5FFF FFFF寄存器名称相对外设基地址的偏移值编号位表读写权限寄存器位功能说明使用C语言封装寄存器:1、总线和外设基地址封装利用地址偏移(1)定义外设基地址(Block2 首地址)(2)定义APB2总线基地址(相对外设基地址偏移固定)(3)定义GPIOX外设基地址(相对APB2总线基地址偏移固定)(4)定义GPIOX寄存器地址(相对GPIOX外设基地址偏移固定)(5)使用 C 语言指针操作寄存器进行读/写//定义外设基地址#define PERIPH_BASE ((unsigned int)0x40000000) 1)//定义APB2 总线基地址#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000) 2)//定义GPIOC 外设基地址#define GPIOC_BASE (AHB1PERIPH_BASE + 0x0800) 3)//定义寄存器基地址这里以GPIOC 为例#define GPIOC_CRL *(unsigned int*)(GPIOC_BASE+0x00) 4)#define GPIOC_CRH *(unsigned int*)(GPIOC_BASE+0x04)#define GPIOC_IDR *(unsigned int*)(GPIOC_BASE+0x08)#define GPIOC_ODR *(unsigned int*)(GPIOC_BASE+0x0C)#define GPIOC_BSRR *(unsigned int*)(GPIOC_BASE+0x10)#define GPIOC_BRR *(unsigned int*)(GPIOC_BASE+0x14)#define GPIOC_LCKR *(unsigned int*)(GPIOC_BASE+0x18)//控制GPIOC 第0 管脚输出一个低电平5)GPIOC_BSRR = (0x01<<(16+0));//控制GPIOC 第0 管脚输出一个高电平GPIOC_BSRR = (0x01<<0);2、寄存器封装利用结构体、外设基地址和寄存器地址偏移typedef unsigned int uint32_t; /*无符号32 位变量*/typedef unsigned short int uint16_t; /*无符号16 位变量*//* GPIO 寄存器列表*/typedef struct{uint32_t CRL; /*GPIO 端口配置低寄存器地址偏移: 0x00 */uint32_t CRH; /*GPIO 端口配置高寄存器地址偏移: 0x04 */uint32_t IDR; /*GPIO 数据输入寄存器地址偏移: 0x08 */uint32_t ODR; /*GPIO 数据输出寄存器地址偏移: 0x0C */uint32_t BSRR; /*GPIO 位设置/清除寄存器地址偏移: 0x10 */uint32_t BRR; /*GPIO 端口位清除寄存器地址偏移: 0x14 */uint16_t LCKR; /*GPIO 端口配置锁定寄存器地址偏移: 0x18 */}GPIO_TypeDef;只要给结构体设置好首地址,就能把结构体内成员的地址确定下来,然后就能以结构体的形式访问寄存器。
STM32中断优先级和开关总中断一,中断优先级:STM32(Cortex-M3)中的优先级概念STM32(Cortex-M3)中有两个优先级的概念——抢占式优先级和响应优先级,有人把响应优先级称作'亚优先级'或'副优先级',每个中断源都需要被指定这两种优先级。
具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套,或者说高抢占式优先级的中断可以嵌套低抢占式优先级的中断。
当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。
如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理哪一个。
既然每个中断源都需要被指定这两种优先级,就需要有相应的寄存器位记录每个中断的优先级;在Cortex-M3中定义了8个比特位用于设置中断源的优先级,这8个比特位可以有8种分配方式,如下:所有8位用于指定响应优先级最高1位用于指定抢占式优先级,最低7位用于指定响应优先级最高2位用于指定抢占式优先级,最低6位用于指定响应优先级最高3位用于指定抢占式优先级,最低5位用于指定响应优先级最高4位用于指定抢占式优先级,最低4位用于指定响应优先级最高5位用于指定抢占式优先级,最低3位用于指定响应优先级最高6位用于指定抢占式优先级,最低2位用于指定响应优先级最高7位用于指定抢占式优先级,最低1位用于指定响应优先级这就是优先级分组的概念。
--------------------------------------------------------------------------------Cortex-M3允许具有较少中断源时使用较少的寄存器位指定中断源的优先级,因此STM32把指定中断优先级的寄存器位减少到4位,这4个寄存器位的分组方式如下:第0组:所有4位用于指定响应优先级第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级第4组:所有4位用于指定抢占式优先级可以通过调用STM32的固件库中的函数NVIC_PriorityGroupConfig()选择使用哪种优先级分组方式,这个函数的参数有下列5种:NVIC_PriorityGroup_0 => 选择第0组NVIC_PriorityGroup_1 => 选择第1组NVIC_PriorityGroup_2 => 选择第2组NVIC_PriorityGroup_3 => 选择第3组NVIC_PriorityGroup_4 => 选择第4组接下来就是指定中断源的优先级,下面以一个简单的例子说明如何指定中断源的抢占式优先级和响应优先级:// 选择使用优先级分组第1组NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);// 使能EXTI0中断NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 指定抢占式优先级别1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 指定响应优先级别0NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);// 使能EXTI9_5中断NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 指定抢占式优先级别0NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 指定响应优先级别1NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);要注意的几点是:1)如果指定的抢占式优先级别或响应优先级别超出了选定的优先级分组所限定的范围,将可能得到意想不到的结果;2)抢占式优先级别相同的中断源之间没有嵌套关系;3)如果某个中断源被指定为某个抢占式优先级别,又没有其它中断源处于同一个抢占式优先级别,则可以为这个中断源指定任意有效的响应优先级别。
stm32学习笔记--spi与iic关于上次说的要改程序的问题,//读ADXL345 寄存器//addr:寄存器地址//返回值:读到的值u8 ADXL345_RD_Reg(u8 addr){u8 temp=0; IIC_Start(); IIC_Send_Byte(ADXL_WRITE); //发送写器件指令temp=IIC_Wait_Ack(); IIC_Send_Byte(addr); //发送寄存器地址temp=IIC_Wait_Ack(); IIC_Start(); //重新启动IIC_Send_Byte(ADXL_READ); //发送读器件指令temp=IIC_Wait_Ack(); temp=IIC_Read_Byte(0); //读取一个字节,不继续再读,发送NAK IIC_Stop(); //产生一个停止条件return temp; //返回读到的值} 这段写寄存器代码,不理解temp 为什么要被频繁的赋值,去掉后,宏观看来对结果没有影响。
第二个不理解的地方是为什么在发送寄存器地址之后要从新启动一次,因为在相似的写寄存器函数中,在相同的位置不存在重启代码。
注释掉该句之后显示ADXL345 error。
这两天主要看了三轴加速度计的程序,虽然例程里的能看懂,但是在四轴里的程序却不那么容易,我甚至不明白为什么他要自己写一个iic 的函数,我打算接下来把它的程序和例程里的程序对照来看,看能不能找到什么头绪。
下面是对以前学过内容的总结:对位的寻址操作为了实现对SARM、I/O 外设空间中某一位的操作,在寻址空间(4GB)另一地方取个别名区空间,从这地址开始,每一个字(32bit)就对应SRAM 或I/O 的一位。
即原来每个字节用一个地址,现在给字节中的每个位一个地址,实现了对位的寻址。
spi 与iic 之间各自的优劣1 硬件连接的优劣SPI 是[单主设备(single-master )]通信协议,这意味着总线中的只有一支中心设备能发起通信。
STM32学习笔记——新建⼯程模板步骤(向原⼦哥学习)1、在创建⼯程之前,先在电脑的某个⽬录下⾯建⽴⼀个⽂件夹,我们先把它命名为Template,后⾯建⽴的⼯程可以放在这个⽂件夹下。
在Template ⼯程⽬录下⾯,新建 3 个⽂件夹USER , CORE , OBJ 以及STM32F10x_FWLib 。
代码⼯程⽂件都是放在 USER ⽬,录CORE ⽤来存放核⼼⽂件和启动⽂件, OBJ 是⽤来存放编译过程⽂件以及 hex ⽂件, STM32F10x_FWLib ⽂件夹顾名思义⽤来存放 ST 官⽅提供的库函数源码⽂件。
已有的 USER ⽬录除了⽤来放⼯程⽂件外,还⽤来存放主函数⽂件main.c,以及其他包括 system_stm32f10x.c等等。
2、在MDK主界⾯,点击 Keil 的菜单:Project -> New Uvision Project ,然后将⽬录定位到刚才建⽴的⽂件夹Template 之下,然后定位到USER ⽬录下⾯,我们的⼯程⽂件就都保存到 USER ⽂件夹下⾯。
⼯程命名为 Template ,点击保存。
3、接下来会出现⼀个选择 Device 的界⾯,就是选择我们的芯⽚型号,这⾥我们定位到STMicroelectronics 下⾯的 STM32F103ZE 。
弹出对话框“Copy STM32 Startup Code to project ….”,询问是否添加启动代码到我们的⼯程中,这⾥我们选择“否”,因为我们使⽤的 ST 固件库⽂件已经包含了启动⽂件。
此时,USER ⽬录下⾯包含三个⽂件。
4、将官⽅的固件库包⾥的源码⽂件复制到我们的⼯程⽬录⽂件夹下⾯。
打开官⽅固件库包,定位到我们之前准备好的固件库包的⽬录:STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver 下⾯,将⽬录下⾯的 src,inc ⽂件夹 copy 到我们刚才建⽴的STM32F10x_FWLib ⽂件夹下⾯。
USART程序分析一 .H文件#ifndef __USART_H#define __USART_H#include <stm32f10x_lib.h>#include "stdio.h"extern u8 USART_RX_BUF[64]; //接收缓冲,最大63个字节.末字节为换行符extern u8 USART_RX_STA; //接收状态标记//如果想串口中断接收,请不要注释以下宏定义//#define EN_USART1_RX 使能串口1接收void uart_init(u32 pclk2,u32 bound);#endif解释:extern 作用域:如果整个工程由多个文件组成,在一个文件中想引用另外一个文件中已经定义的外部变量时,则只需在引用变量的文件中用extern关键字加以声明即可。
可见,其作用域从一个文件扩展到多个文件了。
例子:文件a.c的内容:#include <stdio.h>int BASE=2; //变量定义int exe(int x); //外部函数提前声明int main(int argc, char *agrv[]){int a=10;printf("%d^%d = %d\n",BASE,a,exe(a));return 0;}文件b.c的内容:#include <stdio.h>extern BASE; //外部变量声明int exe(int x){int i;int ret=1;for(i=0;i<x;i++){ret*=BASE;}return ret;}利用gcc工具编译gcc a.c b.c –o demo,再运行./demo,结果为2^10= 1024。
其中,在a.c文件中定义BASE=2,在b.c中引用BASE时,需要用extern关键字声明其为外部变量,否则编译会找不到该变量。
推挽输出与开漏输出的区别推挽输出推挽输出::可以输出高可以输出高,,低电平低电平,,连接数字器件连接数字器件; ;开漏输出开漏输出::输出端相当于三极管的集电极输出端相当于三极管的集电极. . 要得到高电平状态需要上拉电阻才行要得到高电平状态需要上拉电阻才行. . 适合于做电流型的驱动电流型的驱动,,其吸收电流的能力相对强其吸收电流的能力相对强((一般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 的漏极。
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学习笔记(3):系统时钟和SysTick定时器1.STM32的时钟系统在STM32中,一共有5个时钟源,分别是HSI、HSE、LSI、LSE、PLL(1)HSI是高速内部时钟,RC振荡器,频率为8MHz;(2)HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围是4MHz – 16MHz;(3)LSI是低速内部时钟,RC振荡器,频率为40KHz;(4)LSE是低速外部时钟,接频率为32.768KHz的石英晶体;(5)PLL为锁相环倍频输出,严格的来说并不算一个独立的时钟源,PLL 的输入可以接HSI/2、HSE或者HSE/2。
倍频可选择为2 – 16倍,但是其输出频率最大不得超过72MHz。
其中,40kHz的LSI供独立看门狗IWDG使用,另外它还可以被选择为实时时钟RTC的时钟源。
另外,实时时钟RTC的时钟源还可以选择LSE,或者是HSE的128分频。
STM32中有一个全速功能的USB模块,其串行接口引擎需要一个频率为48MHz的时钟源。
该时钟源只能从PLL端获取,可以选择为1.5分频或者1分频,也就是,当需使用到USB模块时,PLL必须使能,并且时钟配置为48MHz 或72MHz。
另外STM32还可以选择一个时钟信号输出到MCO脚(PA.8)上,可以选择为PLL输出的2分频、HSI、HSE或者系统时钟。
系统时钟SYSCLK,它是提供STM32中绝大部分部件工作的时钟源。
系统时钟可以选择为PLL输出、HSI、HSE。
系系统时钟最大频率为72MHz,它通过AHB分频器分频后送给各个模块使用,AHB分频器可以选择1、2、4、8、16、64、128、256、512分频,其分频器输出的时钟送给5大模块使用:(1)送给AHB总线、内核、内存和DMA使用的HCLK时钟;(2)通过8分频后送给Cortex的系统定时器时钟;(3)直接送给Cortex的空闲运行时钟FCLK;(4)送给APB1分频器。
STM32学习笔记——电源管理STM32的3种低功耗模式:1、睡眠模式__WFI(); __WFE();外部中断设置为中断模式时,__WFI()和__WFE()都能被中断唤醒;外部中断设置为事件模式时,只能唤醒__WFE();用事件唤醒时会唤醒2次,未找到原因(因按键性能不良,抖动严重);另外事件产生时不会置位标志位,不需要清除。
从睡眠模式返回时不需要重新设置系统时钟。
唤醒任意中断或事件唤醒对应的WFE、WFI.2、停机模式使用void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry);进入停机模式;(1) 初始化用于唤醒的中断按键,配置为中断或事件;(2) 设置停止状态时的FLASH供电或掉电;(3) 选择电压调节器的工作模式并进入停止状态;(4) 使用按键中断唤醒芯片;(5) 重启HSE时钟,使系统完全恢复停止前的状态。
重启HSE时钟函数:SYSCLKConfig_STOP();static void SYSCLKConfig_STOP(void) /* After wake-up from STOP reconfigure the system clock */{RCC_HSEConfig(RCC_HSE_ON); /* 使能HSE */while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); /* 等待HSE 准备就绪*/RCC_PLLCmd(ENABLE); /* 使能PLL */while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); /* 等待PLL 准备就绪*/RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); /* 选择PLL作为系统时钟源*/while (RCC_GetSYSCLKSource() != 0x08); /* 等待PLL被选择为系统时钟源*/}当进入待机和停止模式时,HSEON该位由硬件清零,外部振荡器HSE被关闭,所以如果使用到HSE,则唤醒后需要重新设置使用的HSE;当从待机和停止模式返回或用作系统时钟的外部4-16MHz振荡器发生故障时,HSI位由硬件置’1’启动内部8MHz的RC振荡器HSI 。
STM32学前班教程之一:为什么是它经过几天的学习,基本掌握了STM32的调试环境和一些基本知识。
想拿出来与大家共享,笨教程本着最大限度简化删减STM32入门的过程的思想,会把我的整个入门前的工作推荐给大家。
就算是给网上的众多教程、笔记的一种补充吧,所以叫学前班教程。
其中涉及产品一律隐去来源和品牌,以防广告之嫌。
全部汉字内容为个人笔记。
所有相关参考资料也全部列出。
:lol教程会分几篇,因为太长啦。
今天先来说说为什么是它——我选择STM32的原因。
我对未来的规划是以功能性为主的,在功能和面积之间做以平衡是我的首要选择,而把运算放在第二位,这根我的专业有关系。
里面的运算其实并不复杂,在入门阶段想尽量减少所接触的东西。
不过说实话,对DSP的外设并和开发环境不满意,这是为什么STM32一出就转向的原因。
下面是我自己做过的两块DSP28的全功能最小系统板,在做这两块板子的过程中发现要想尽力缩小DSP的面积实在不容易(目前只能达到50mm×45mm,这还是没有其他器件的情况下),尤其是双电源的供电方式和1.9V的电源让人很头疼。
后来因为一个项目,接触了LPC2148并做了一块板子,发现小型的ARM7在外设够用的情况下其实很不错,于是开始搜集相关芯片资料,也同时对小面积的AVR和51都进行了大致的比较,这个时候发现了CortexM3的STM32,比2148拥有更丰富和灵活的外设,性能几乎是2148两倍(按照MIPS值计算)。
正好2148我还没上手,就直接转了这款STM32F103。
与2811相比较(核心1.8V供电情况下),135MHz×1MIPS。
现在用STM32F103,72MHz×1.25MIPS,性能是DSP的66%,STM32F103R型(64管脚)芯片面积只有2811的51%,STM32F103C型(48管脚)面积是2811的25%,最大功耗是DSP的20%,单片价格是DSP的30%。
1. STM32的Timer简介STM32中一共有11个定时器,其中2个高级控制定时器,4个普通定时器和2个基本定时器,以及2个看门狗定时器和1个系统嘀嗒定时器。
其中系统嘀嗒定时器是前文中所描述的SysTick,看门狗定时器以后再详细研究。
今天主要是研究剩下的8个定时器。
其中TIM1和TIM8是能够产生3对PWM互补输出的高级登时其,常用于三相电机的驱动,时钟由APB2的输出产生。
TIM2-TIM5是普通定时器,TIM6和TIM7是基本定时器,其时钟由APB1输出产生。
由于STM32的TIMER功能太复杂了,所以只能一点一点的学习。
因此今天就从最简单的开始学习起,也就是TIM2-TIM5普通定时器的定时功能。
2基本定时器TIM6-TIM72.1 时钟基本特征基本定时器TIM6和TIM7各包含一个16位自动装载计数器,由各自的可编程预分频器驱动。
它们可以作为通用定时器提供时间基准,特别地可以为数模转换器(DAC) 提供时钟。
实际上,它们在芯片内部直接连接到DAC并通过触发输出直接驱动DAC。
这2个定时器是互相独立的,不共享任何资源。
2.2 TIM6-7主要特征TIM6和TIM7定时器的主要功能包括:● 16位自动重装载累加计数器● 16位可编程( 可实时修改)预分频器,用于对输入的时钟按系数为1~65536 之间的任意数值分频● 触发DAC的同步电路● 在更新事件(计数器溢出)时产生中断/DMA 请求图144 基本定时器框图2.3 计数器模式TIM6-TIM7可以由向上计数。
向上计数模式中,计数器从0计数到自动加载值(TIMx_ARR计数器内容),然后重新从0开始计数并且产生一个计数器溢出事件。
2.4 编程步骤1. 配置优先级;2. 使能时钟3. 配置GPIO;4. 配置TIME;5.使能计数器;6.开中断;7.清除标志位;具体配置如下:(1) NVIC_Configuration(void);配置优先级(2) void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)使能时钟(3) void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef*GPIO_InitStruct);配置GPIO(4) TIM_Configuration (void);配置TIM6/TIM7(5) TIM_Cmd(TIM7, ENABLE);使能定时器(6) TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE);使能中断(7) TIM_ClearFlag(TIM7, TIM_FLAG_Update);清除标志位步骤(4)中的预分频系数用来确定TIMx所使用的时钟频率,具体计算方法为:CK_INT/(TIM_Perscaler+1)。
New Project
Step 1: Add same new file in somewhere
1.1_stm_libray file is for CMSIS and STM32F4xx_StdPeriph_Driver
This two include all of the chip’s massage(Cortex-M4 and Periph).
2.1_ stm_user is include the template for create a New Project.
ER_Project is for user to save new project.
Step 2: add new groups and add file to it
Step 3: click target Options to configure the chainline
E_STDPERIPH_DRIVER STM32F40_41xxx is to tell chainline we will use
the library and what processor we are using.
2.Inculde Paths is to set chainline path for header file.
We should add three path for it ,first is the project path, second is the
CMSIS’s Include file’s path that is for Cortex – M4,third is
STM32F4xx_StdPeriph_Driver’s Icnclude file that is for Periph.
Debug:
1.编译时提示warning: #1-D: last line of file ends without a newline
解决办法:
将光标移到提示告警的代码最后一行(有代码的那一行)
然后按住del键,直到确定下面没有回车行
最后回车一下或多下即可
2. #define STM32F4XX STM32F40XX为什么在编译器设置里还要在keil中
options->C++->Define中定义USE_STDPERIPH_DRIVER,STM32F4XX?warning:
#47-D: incompatible redefinition of macro "STM32F4XX"
解决办法:
不需要在Keil target options - C/C++中预先定义STM32F40XX
Programming Note:
1.规范的位操作
1.位清0操作
2.位置1操作
3.位取反操作
2.STM32F4 系统时钟设置
(1)Void RCC_HCLK_Config(uint32_t RCC_SYSCLK)
3.GPIO 配置: 以配置GPIOD5为例
voidLED_GPIO_Config(void)
{
/* define GPIO_InitTypeDef structure for manipulating GPIO */
GPIO_InitTypeDef* GPIOD5_InitStruct;
/* enable GPIOD's clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);
/* select GPIO mode */
GPIOD5_InitStruct->GPIO_Mode = GPIO_Mode_OUT;
/* select output type --> output push-pull */
GPIOD5_InitStruct->GPIO_OType = GPIO_OType_PP;
/* set output speed */
GPIOD5_InitStruct->GPIO_Speed = GPIO_Speed_50MHz;
/* select the pins */
GPIOD5_InitStruct->GPIO_Pin = GPIO_Pin_5;
/* select pull up and pull down register --->pull up */
GPIOD5_InitStruct->GPIO_PuPd = GPIO_PuPd_UP;
/* GPIOD init */
GPIO_Init(GPIOD,GPIOD5_InitStruct);
/* turn off the light */
GPIO_ResetBits(GPIOD,GPIO_Pin_5);
}
ART 异步通信通信配置
/* define an stucture for init */
USART_InitTypeDefUSART_InitStuct;
/* define an structure for GPIO */
GPIO_InitTypeDefGPIO_InitStruct;
/* Periphery device clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
/* USART Configure */
USART_ART_BaudRate = 9600; //BaudRate
USART_ART_WordLength = USART_WordLength_8b; //data bits
USART_ART_StopBits = USART_StopBits_1; //stop bits
USART_ART_Parity = USART_Parity_No; //parity bit
USART_ART_HardwareFlowControl =
USART_HardwareFlowControl_None;
USART_ART_Mode = USART_Mode_Rx | USART_Mode_Tx;
/* GPIOA Tx Configure */
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //select alternate
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; // push pull
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; // no pull up register
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8; //select GPIOA9 --Tx
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOD, &GPIO_InitStruct); //GPIOA Txinitializatoin
/* GPIOA Rx Configure */
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; // flaoting input
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; //select GPIOA10 --Rx
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD, &GPIO_InitStruct); //GPIOA Rx initializatoin
GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_USART3);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_USART3);
/* call UART_Init */
USART_Init(USART3, &USART_InitStuct);
/* UART enable */
USART_Cmd(USART3, ENABLE);
(1)如果只是发送数据到PC,则可只配置Tx。