stm32学习笔记(狼牙整理)
STM32学习笔记

STM32学习笔记1、GPIO函数:输出:HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET);//此例以PA12⼝为例HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_SET); //此例以PA12⼝为例HAL_GPIO_ TogglePin(GPIOA,GPIO_PIN_12); //此例以PA12⼝为例2、串⼝函数:1、串⼝发送/接收函数HAL_UART_Transmit();串⼝轮询模式发送,使⽤超时管理机制HAL_UART_Receive();串⼝轮询模式接收,使⽤超时管理机制HAL_UART_Transmit_IT();串⼝中断模式发送HAL_UART_Receive_IT();串⼝中断模式接收HAL_UART_Transmit_DMA();串⼝DMA模式发送HAL_UART_Transmit_DMA();串⼝DMA模式接收2、串⼝中断函数HAL_UART_TxHalfCpltCallback();⼀半数据发送完成时调⽤HAL_UART_TxCpltCallback();数据完全发送完成后调⽤HAL_UART_RxHalfCpltCallback();⼀半数据接收完成时调⽤HAL_UART_RxCpltCallback();数据完全接受完成后调⽤HAL_UART_ErrorCallback();传输出现错误时调⽤例程:串⼝接收中断uint8_t aTxStartMessages[] = "\r\n******UART commucition using IT******\r\nPlease enter 10 characters:\r\n";uint8_t aRxBuffer[20];2、在main函数中添加两个语句通过串⼝中断发送aTxStartMessage数组的数据和接收数据10个字符,保存在数组aRxBuffer中HAL_UART_Transmit_IT(&huart1 ,(uint8_t*)aTxStartMessages,sizeof(aTxStartMessages)); //sizeof()可读取⽬标长度HAL_UART_Receive_IT(&huart1,(uint8_t*)aRxBuffer,10);3、在main.c⽂件后⾯添加中断接收完成函数,将接收到的数据⼜通过串⼝发送回去。
STM32学习笔记

串口:一. USART_ITConfig(USART1, USART_IT_TXE, ENABLE):只要发送寄存器为空,就会一直有中断,因此,要是不发送数据时,把发送中断关闭,只在开始发送时,才打开。
二.以下是字符发送的配置过程,注意第6点,在设置USART_CR1中的TE位时,会发送一个空闲帧作为第一次数据发送,所以即便你执行了USART_ClearFlag(USART1, USART_FLAG_TC); (这个函数肯定在空闲帧数据发送完成前执行),所以当空闲帧发送完后,就进入发送完成中断。
配置步骤:1. 通过在USART_CR1寄存器上置位UE位来激活USART2. 编程USART_CR1的M位来定义字长。
3. 在USART_CR2中编程停止位的位数。
4. 如果采用多缓冲器通信,配置USART_CR3中的DMA使能位(DMA T)。
按多缓冲器通信中的描述配置DMA寄存器。
5. 利用USART_BRR寄存器选择要求的波特率。
6. 设置USART_CR1中的TE位,发送一个空闲帧作为第一次数据发送。
7. 把要发送的数据写进USART_DR寄存器(此动作清除TXE位)。
在只有一个缓冲器的情况下,对每个待发送的数据重复步骤7。
8. 在USART_DR寄存器中写入最后一个数据字后,要等待TC=1,它表示最后一个数据帧的传输结束。
当需要关闭USART或需要进入停机模式之前,需要确认传输结束,避免破坏最后一次传输。
解决的办法:方法一在执行USART_ITConfig(USART1, USART_IT_TC, ENABLE); 之前,先延时一段时间,基本上比一个字符发送的时间长一点就可以了,然后再执行USART_ClearFlag(USART1, USART_FLAG_TC);方法二:在执行USART_ITConfig(USART1, USART_IT_TC, ENABLE); 之前,USART_ClearFlag(USART1, USART_FLAG_TC);while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET){; //等待空闲帧发送完成后再清零发送标志}USART_ClearFlag(USART1,USART_FLAG_TC);三.TXE:发送缓冲器空闲标志RXNE:接收缓冲区非空IAP:一.问:这几天在折腾STM32的IAP,参考了两个例程,一个AN2557,然后一个就是标准外设库内的flash例程总结IAP:1.Flash解锁 FLASH_Unlock();2.清除Flash所有的未完成的标志位 FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);3.根据文件大小擦除Flashfor(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE ); EraseCounter++){FLASHStatus = FLASH_ErasePage(StartAddr + (FLASH_PAGE_SIZE * EraseCounter));}4.编程Flashwhile((Address < EndAddr) && (FLASHStatus == FLASH_COMPLETE)){FLASHStatus = FLASH_ProgramWord(Address, Data);Address = Address + 4;}5.检验编入数据的正确性while((Address < EndAddr) && (MemoryProgramStatus != FAILED)){if((*(__IO uint32_t*) Address) != Data){MemoryProgramStatus = FAILED;}Address += 4;}在以上几步中,如果上面没有问题的话,提出下面几个疑问1.假如我的应用程序的地址应该从0x8003000开始,那么我把后面的页全部擦除是否可以? 虽然我的程序可能只占到0x8003000-0x8005000 那么这之后的页是否也可以一并擦除?2.在编程的时候有个很小的问题,因我的数据都是以字节(byte)的形式储存的,在写的时候因为只能以半字(16位)或一个字(32位)的方式编程,那么如果我的bin文件的最后一个字节并不够两个字节,怎么办?举例:我的bin文件的大小是501个字节(8位),我的写入方法是这样的:data[501] = {X,X,X...}//应用程序bin文件内容temp = data[0];temp = temp << 8;temp |= data[1];temp = temp << 8;temp |= data[2];teme = temp << 8;teme |= data[3];//待写入得数据FLASHStatus = FLASH_ProgramWord(Address, temp);//写入flash如果像这样的话,那么不能被4整除的那一个字节怎么办?3.IAP程序中有一处一直很迷惑,不能理解/* Test if user code is programmed starting from address "ApplicationAddress" */if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000){ /* Jump to user application */JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);Jump_To_Application = (pFunction) JumpAddress;/* Initialize user application's Stack Pointer */__set_MSP(*(__IO uint32_t*) ApplicationAddress);Jump_To_Application();}程序的整体是要跳出IAP引导区跳到应用程序区.那么这句判断的依据是什么?if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)倘若我今天的程序是重0x8003000处开始,那么明天我升级一个程序,他的开始是0x80080000呢?这里需要改吗?0x2FFE0000 0x20000000 这两个数我在AN2557的例子代码里反复寻找,并没有哪里出现,那么又是怎么跟用户的应用程序关联的呢?还有如果将上面的例子直接这样更改,是否可以达到跳转到应用程序区的目的呢?/* Jump to user application */JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4); //这里为何要+4 ?+了4不就跳过出应用程序的入口了吗?Jump_To_Application = (pFunction) JumpAddress;/* Initialize user application's Stack Pointer */__set_MSP(*(__IO uint32_t*) ApplicationAddress);Jump_To_Application();4.关于Flash的写保护问题,在3.0标准外设库中Flash还有另外一个例子,就是关于保护的无疑flash的保护是对程序的一个安全保障,但目前我买的新片子(未进行过任何保护方面的操作)中,是否不需要考虑这些问题,直接擦除,然后编程即可?5.有什么理由要“今天的程序是重0x8003000处开始,明天又升级一个程序,他的开始是呢”?第1没有必要,第2是自寻烦恼。
stm32 学习笔记

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学习笔记

stm32学习笔记Stm32学习笔记—寄存器版本养成良好的编程能⼒很重要否则还以后的⽣活和⼯作当中会吃很⼤的亏的!⼀、在MDK中进⾏对stm32的学习中⽤寄存器进⾏学习只需要很简单的操作,⽐起⽤库函数进⾏学习⼤⼤降低了学习的难度。
1)⾸先将system⽂件夹中的delay、sys以及usart三个⽂件夹复制到⼯程⽂件夹中并添加进⼯程当中去,然后再把⼀个启动⽂件复制到⼯程当中去并添加即可。
⼆、LED跑马灯的学习:1)编写LED初始化函数,这其中包括GPIOX时钟的使能,然后就是对应LED的端⼝的设置,其中包括输⼊输出模式以及输出的形式(是⾼电平还是低电平);2)编写完成之后就是调⽤LED初始化函数进⾏试验。
代码如下:void LED_Init(void){RCC->APB2ENR|=1<<3; //使能PORTB时钟RCC->APB2ENR|=1<<6; //使能PORTE时钟GPIOB->CRL&=0XFF0FFFFF; //输出模式GPIOB->CRL|=0X00300000;//PB.5 推挽输出GPIOB->ODR|=1<<5; //PB.5 输出⾼GPIOE->CRL&=0XFF0FFFFF;GPIOE->CRL|=0X00300000;//PE.5推挽输出GPIOE->ODR|=1<<5; //PE.5输出⾼}3)stm32中的IO⼝初始化之后默认的形式是下拉的。
下⾯是⼏种常见的输⼊形式,最好记住三、⽤串⼝发送和接受数据1)⾸先肯定是使能串⼝时钟和串⼝所对应的io⼝时钟,设置io⼝的输⼊输出模式,然后复位串⼝、停⽌复位,设置波特率和校检位。
⾄此串⼝已经初始化完毕。
串⼝的波特率是根据以下公式算的以下是初始化串⼝的函数void uart_init(u32 pclk2,u32 bound){float temp;u16 mantissa;u16 fraction;temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIVmantissa=temp; //得到整数部分fraction=(temp-mantissa)*16; //得到⼩数部分mantissa<<=4;//将最后的⼀个16进制位移开再与⼩数位相加mantissa+=fraction;RCC->APB2ENR|=1<<2; //使能PORTA⼝时钟RCC->APB2ENR|=1<<14; //使能串⼝时钟GPIOA->CRH&=0XFFFFF00F;//IO状态设置GPIOA->CRH|=0X000008B0;//IO状态设置RCC->APB2RSTR|=1<<14; //复位串⼝1RCC->APB2RSTR&=~(1<<14);//停⽌复位//波特率设置USART1->BRR=mantissa; // 波特率设置USART1->CR1|=0X200C; //1位起始,⽆校验位.#if EN_USART1_RX //如果使能了接收//使能接收中断USART1->CR1|=1<<8; //PE中断使能USART1->CR1|=1<<5; //接收缓冲区⾮空中断使能MY_NVIC_Init(3,3,USART1_IRQn,2);//组2,最低优先级#endif}四、外部中断事件1)初始化IO⼝为输⼊。
STM32学习笔记

STM32学习笔记MDK不会让你直接在入口参数处设置一个简单的字,因为这样代码可读性太差MDK一般把取值范围的宏定义放在判断有效性语句的上方,这样是为了方便大家查找可以通过|(或)的方式同时初始化多个IO口。
这样操作的前提是,他们的Mode和Speed参数相同,因为Mode和Speed参数并不能一次定义多种在tm32f10某.h看那些外设是挂载在那个总线之下GPIO操作步骤为:1)使能IO口时钟。
调用函数为RCC_APB2PeriphClockCmd()。
2)初始化IO参数。
调用函数GPIO_Init();3)操作IO。
按键一端接高电平时另一端接I/O口则I/O口设置为下拉输入,因为按键按下时I/O口变成高电平;反之接低电平时I/O口设置为上拉输入因为按键按下时I/O口状态为低电平Config意为配置voidNVIC_PriorityGroupConfig(uint32_tNVIC_PriorityGroup);这个函数的作用是对中断的优先级进行分组,这个函数在系统中只能被调用一次,一旦分组确定就最好不要更改当接收到从电脑发过来的数据,把接收到的数据保存在USART_R某_BUF中,同时在接收状态寄存器(USART_R某_STA)中计数接收到的有效数据个数,当收到回车(回车的表示由2个字节组成:0某0D和0某0A)的第一个字节0某0D时,计数器将不再增加,等待0某0A的到来,而如果0某0A没有来到,则认为这次接收失败,重新开始下一次接收。
如果顺利接收到0某0A,则标记USART_R某_STA的第15位,这样完成一次接收,并等待该位被其他程序清除,从而开始下一次的接收,而如果迟迟没有收到0某0D,那么在接收数据超过USART_REC_LEN的时候,则会丢弃前面的数据,重新接收。
USART初始化需要设置的参数为:波特率,字长,停止位,奇偶校验位,硬件数据流控制,模式(收,发)。
①串口时钟使能,GPIO时钟使能②串口复位③GPIO端口模式设置④串口参数初始化⑤初始化NVIC并且开启中断⑥使能串口SyTick是系统滴答计时器在E某TI_GetITStatu函数中会先判断这种中断是否使能,使能了才去判断中断标志位,而E某TI_GetFlagStatu直接用来判断状态标志位。
详细的STM32单片机学习笔记

详细的STM32单片机学习笔记STM32单片机学习笔记1、AHB系统总线分为APB1(36MHz)和APB2(72MHz),其中21,意思是APB2接高速设备2、Stm32f10x.h相当于reg52.h(里面有基本的位操作定义),另一个为stm32f10x_conf.h 专门控制外围器件的配置,也就是开关头文件的作用3、HSE Osc(High Speed External Oscillator)高速外部晶振,一般为8MHz,HSI RC(High Speed InternalRC)高速内部RC,8MHz4、LSE Osc(Low Speed External Oscillator)低速外部晶振,一般为32.768KHz,LSI RC (Low Speed InternalRC)低速内部晶振,大概为40KHz左右,提供看门狗时钟和自动唤醒单元时钟源5、SYSCLK时钟源有三个来源:HSI RC、HSE OSC、PLL6、MCO[2:0]可以提供4源不同的时钟同步信号,PA87、GPIO口貌似有两个反向串联的二极管用作钳位二极管。
8、总线矩阵采用轮换算法对系统总线和DMA进行仲裁9、ICode总线,DCode总线、系统总线、DMA总线、总线矩阵、AHB/APB桥10、在使用一个外设之前,必须设置寄存器RCC_AHBENR来打开该外设的时钟11、数据字节以小端存储形式保存在存储器中12、内存映射区分为8个大块,每个块为512MB13、FLASH的一页为1K(小容量和中容量),大容量是2K。
14、系统存储区(SystemMemory)为ST公司出厂配置锁死,用户无法编辑,用于对FLASH 区域进行重新编程。
所以我们烧写程序务必选择BOOT1 = 0,这样通过内嵌的自举程序对。
Stm32中文手册学习笔记

Stm32中⽂⼿册学习笔记Stm32相对于51复杂了太多,之前⾃⼰学习⽅法不对,所以导致花了时间也没什么效果,现在⼯作了⾃⼰也知道该怎么来更好学习了,准备花两周左右看⼀下stm32中⽂⼿册及固件库⼿册,然后再按照正点原⼦的不完全⼿册结合这开发板来学习,也记下学习笔记总结学习、加深记忆。
此次的学习是以STM32F103RBT6作为核⼼MCU的,其有128k flash、20k sram、2个spi、3个串⼝、1个usb、1个can、2个12位的adc、rtc以及51个可⽤的IO⼝。
笔记⼀存储器及总线架构1.Stm32主系统由以下部分构成:●四个驱动单元:─ Cortex?-M3内核DCode总线(D-bus),和系统总线(S-bus) ─通⽤DMA1和通⽤DMA2●四个被动单元─内部SRAM─内部闪存存储器─ FSMC─ AHB到APB的桥(AHB2APBx),它连接所有的APB设备。
2.在每⼀次复位以后,所有除SRAM和FLITF以外的外设都被关闭,在使⽤⼀个外设之前,必须设置寄存器RCC_AHBENR来打开该外设的时钟。
所以以后编程的时候要记住设置RCC_AHBENR来使能外设。
3.memory map是很重要的,以前⼀直没有引起⾜够的重视,程序存储器、数据存储器、寄存器和输⼊输出端⼝被组织在同⼀个4GB的线性地址空间内。
4. 两个位段(bit-band)区,下⾯的映射公式给出了别名区中的每个字是如何对应位带区的相应位的:bit_word_addr = bit_band_base + (byte_offset×32) + (bit_number×4)其中: bit_word_addr是别名存储器区中字的地址,它映射到某个⽬标位。
bit_band_base是别名区的起始地址。
byte_offset是包含⽬标位的字节在位段⾥的序号bit_number是⽬标位所在位置(0-31)例⼦:下⾯的例⼦说明如何映射别名区中SRAM地址为0x20000300的字节中的位2: 0x22006008 =0x22000000 + (0x300×32) + (2×4). 对0x22006008地址的写操作与对SRAM中地址0x20000300字节的位2执⾏读-改-写操作有着相同的效果。
STM32一部分学习笔记

1、迷你版stm32共有64个引脚,分为4组ABCD,每组16个引脚
2、关于BSRR、BRR、ODR寄存器的区别于联系(BSRR可以只对一位操作而不影响其他位)
3、IO口时钟使能位设置函数: stm32f10x_rcc.h中第692、693、694行的函数:
RCC_AHBPeriphClockCmd
RCC_APB2PeriphClockCmd
RCC_APB1PeriphClockCmd
4、IO口使能参数定义在stm32f10x_rcc.h中的466行--554行:
5、关于IO口使能设置的方式:①首先查看硬件,找到对应要使用的IO口
②然后找到系统IO口使能参数的定义
③然后确定使能的位设置函数(RCC_AHBP eriphClockCmd,
RCC_APB2PeriphClockCmd,RCC_APB1PeriphClockCmd
中的一个)
④最后在main函数里面设置使能。
MDK:
6、GPIO寄存器描述:《STM32中文参考手册_V10》第八章。
其中,-GPIOx_CRL和-GPIOx_CRH用于配置GPIO的八种模式和三种最大输出速度。
-GPIOx_IDR用于读取IO口输入的电平(0或者1)。
-GPIOx_ODR和-GPIOx_BSRR以及-GPIOx_BRR都是用来设置IO口的输出(0或者1)。
以下为详细解释:
①、-GPIOx_CRL:32位寄存器,只能配置低八位的IO口。
STM32学习笔记(初学者快速入门

STM32学习笔记(初学者快速入门STM32 学习笔记从51 开始单片机玩了很长时间了有51PICAVR 等等早就想跟潮流玩玩ARM 但一直没有开始原因-----不知道玩了ARM 可以做什么对我自己而言如果为学习而学习肯定学不好然后cortex-m3 出来了据说这东西可以替代单片机于是马上开始关注也在第一时间开始学习可惜一开始就有点站错了队选错了型仍是对我自己而言我希望这种芯片应该是满大街都是随便哪里都可以买得到但我选的第一种显然做不到为此大概浪费了一年多时间吧现在回到对我来说是正确的道路上来啦边学边写点东西这里写的是我的学习的过程显然很多时候会是不全面的不系统的感悟式的甚至有时会是错误的有些做法会是不专业的那么为什么我还要写呢这是一个有趣的问题它甚至涉及到博客为什么要存在的问题显然博客里面的写的东西其正确性权威性大多没法和书比可为什么博客会存在呢理由很多我非专家只说我的感慨我们读武侠小说总会有一些创出独门功夫的宗师功夫极高然后他的弟子则基本上无法超越他我在想这位宗师在创造他自己的独门功夫时必然会有很多的次的曲折弯路甚至失败会浪费他的很多时间而他教给弟子时则已去掉了这些曲折和弯路当然更不会把失败教给弟子按理说效率应该更高可是没用弟子大都不如师为什么呢也许知识本身并不是最重要的获取知识的过程才是最重要的也许所谓的知识并不仅仅是一条条的结论而是附带着很多说不清道不明的东西如植物的根一条主根上必带有大量的小小的触须闲话多了些就权当前言了下面准备开始一条件的准备我的习惯第一步是先搭建一个学习的平台原来学51PICAVR 时都是想方设法自己做些工具实验板之类现在人懒了直接购买成品了硬件电路板火牛板软件有keil 和iar 可供选择网上的口水仗不少我选keil理由很简单这个我熟目前要学的知识中软硬件我都不熟所以找一个我有点熟的东西就很重要在我相当熟练之前肯定不会用到IAR如果真的有一天不得不用IAR 相信学起来也很容易因为这个时候硬件部分我肯定很熟了再加上有keil 的基础所以应该很容易学会了调试工具JLINK V8 这个不多说了价格便宜又好用就是它了二热身网上选购的付了款就是等了拿到包裹端详良久起身沐浴更衣焚香总得先吃晚饭洗澡再点个电蚊香什么的吧拆包细细端详做工精良尤其那上面的32 吋屏越看越喜欢接下来就是一阵折腾了装JLINK 软件给板子通电先试试JLINK 能不能与电脑和板子通信上了真顺一点问题也没有于是准备将附带的程序一个一个地写进去试一试一检查大部分例子的HEX 文件并没有给出这要下一步自己生成但是几个大工程的例子都有HEX 文件如MP3如UCCGI 测试等写完以后观察程序运行的效果因为之前也做过彩屏的东西知道那玩艺代码量很大要流畅地显示并不容当时是用AVR 做的在18 吋屏上显示一幅画要有一段时间现在看起来用STM32 做的驱动显示出来的画面还是很快的不过这里显示的大部分是自画图并没有完整地显示一整幅的照片所以到底快到什么程度还不好说看来不久以后这可以作为一个学习点的一个晚上过去了下一篇就是要开始keil 软件的学习了STM32 学习笔记2本想着偷点懒的没想到竞被加了精没办法啦只能勤快点啦硬件调通后就要开始编程了编程的方法有两种一种是用st 提供的库另一种是从最底层开始编程网上关于使用哪种方法编程的讨论很多据说用库的效率要低一些但是用库编程非常方便所以我还是从库开始啦库是ST 提供的怎么说也不会差到哪里再说了用32 位ARM 的话开发的观念也要随之改变一点了说说我怎么学的吧找个例子如GPIO可以看到其结构如下SOURCE 文件夹- APP 文件夹-CMSIS 文件夹-STM32F10x_StdPeriph_Driver 文件夹Lis 文件夹OBJ 文件夹其中SOURCE 中保存的是应用程序其中又有好多子文件夹而CMSIS 文件夹中和STM32F10x_StdPeriph_Driver 文件夹中是ST 提供的库这样如果要做新的工程只要将这个文件夹整个复制过来就行其中APP 中保存自己的代码因为我们用51 单片机时一般比较简单有时就一个文件所以通常不设置专门的输出文件夹而这里做开发通常会有很多个文件加入一个工程中编译过程中会产生很多中间文件因此设置专门的文件夹LIS 和OBJ 用来保存中间文件下面就将设置简单描述一下将复到过来的GPIO 根目录下的所有文件删除因为我们要学着自己建立工程用菜单Project-- New uVision Porject建立新的工程选择目标器件为STM32103VC这个过程与建立51 单片机的工程没有什么区别这里就偷点懒不上图了接下来看一看怎么设置点那个品字形打开对话框这里就给个图了相信有一定操作基础的人应该会用顺便提一下原来用VC或者IAR 时总觉得它们的一个功能就是建立一个是Debug 组和Release 组这个功能挺好的从这个图可在Keil 里也是一样可以建的将刚才那个文件夹图中CMSIS 中的文件加入CMSIS 组一共3 个其中\Source\CMSIS\Core\CM3 有两个C 语言源程序文件全部加入另外还有一个在\Source\CMSIS\Core\CM3\startup\arm 文件夹中这个文件夹中有4 个s 文件我们选择其中的startup_stm32f10x_hds 文件这是根据项目所用CPU 来选择的我们用的CPU 是103VC 的属于高密度的芯片所以选这个至于LIB 中的文件就在这儿\Source\STM32F10x_StdPeriph_Driver\src 啦这里有很多个文件把什么文件加进去呢怕麻烦的话把所有文件全部加进去这并不会增加编译后的代码量但会增加很多的编译时间接下来设定目标输出文件夹上面这个图怎么出来的就不说啦单击Select Foler for Objects在弹出来的对话框中选择OBJ 文件夹同样方法选择List 文件的输出文件夹设置好后如果直接编译是不行的会出错还需要提供头文件所在位置单击cC标签页第一次进入时Include Paths 文本框中是空白的点击其后的按钮打开对话框增加相应的路径这样路径就设好了单击OK回到上一界面然后再单击OK退出设置即可编译链接下一会要试一试新的312 版的库效果如何了STM32 学习笔记3升级库光盘中所带的例子是310 的另外还有一个312 的我试着将312 的库替代原来的库还真有问题下面就简述问题及解决方法1将库文件解压库文件名是stm32f10x_stdperiph_libzip解压后放在任意一个文件夹中2 由于原作者做了很好的规划每一个项目中都分成三个文件夹并且在source 文件夹中又做了3 个文件夹其中APP 文件夹是放自己写的文件的其他的两个是从库中复制过来的因此想当com 版本中相同的两个文件夹CMSIS 和STM32F10x_StdPeriph_Driver 直接复制过来以为一切OK结果一编译出来一堆错误其中有错误Source\App\mainc 7 error 20 identifier "GPIO_InitTypeDef" is undefined还有大量的警告Source\STM32F10x_StdPeriph_Driver\src\stm32f10x_flashc 130 warning 223-D function "assert_param" declared implicitly看了看在APP 文件夹中还有一些不属于自己的东西stm32f10x_confhstm32f10x_ithstm32f10x_itc打开一看果然是310版本的没说的换找到STM32F10x_StdPeriph_Licom\Project\Template 文件夹用里面的同样的文件替换掉这几个文件这回应该万事大吉了吧再一看依然如故没办法了只好细细研究了通过观察发现原来可以编译通过的工程在mainc 下面挂满了h 文件而这个通不过的则少得很这是编译能通过的工程这是编译通不过的工程显然有些文件没有被包含进来一点一点跟踪发现大部分的头文件都包含在stm32f10x_confh 中而这个文件又出现在stm32f10xh 中其中有这样的一行ifdef USE_STDPERIPH_DRIVERinclude "stm32f10x_confh"endif看来是这个USE_STDPERIPH_DRIVER 没有被定义啊于是人为地去掉条件ifdef USE_STDPERIPH_DRIVERinclude "stm32f10x_confh"endif再次编译果然就OK 了可是可是也不能就这么去掉啊怎么办呢万能的网啊一搜果然就有了到设置 CC页面在那个define 中加入USE_STDPERIPH_DRIVERSTM32F10X_HD当然去掉条件编译前面的注释回到原样再次编译一切顺利可是原来的工程例子也没有加这个啊怎么回事呢再次打开原来的例子找到stm32f10xh可以看到有这么一行而新的stm32f10xh 中则是这样的原com 版的stm32f10xh 被人为地修改了一下所以不在define 中定义也不要紧而新com 则不行了至此简单的升级搞定本文见于好多地方但查询后未能确定其原始出处及作者故这里说明是转贴但作者和原始出处信息就无法提供了如果原作者看到请跟贴说明知情者也请跟贴说明ARM 中的RORW 和ZI DATA一直以来对于ARM 体系中所描述的RORW 和ZI 数据存在似是而非的理解这段时间对其仔细了解了一番发现了一些规律理解了一些以前书本上有的但是不理解的东西我想应该有不少人也有和我同样的困惑因此将我的一些关于RORW 和ZI 的理解写出来希望能对大家有所帮助要了解RORW 和ZI 需要首先了解以下知识ARM 程序的组成此处所说的ARM 程序是指在ARM 系统中正在执行的程序而非保存在ROM中的bin 映像image文件这一点清注意区别一个ARM 程序包含3 部分RORW 和ZIRO 是程序中的指令和常量RW 是程序中的已初始化变量ZI 是程序中的未初始化的变量由以上3 点说明可以理解为RO 就是readonlyRW 就是readwriteZI 就是zeroARM 映像文件的组成所谓ARM 映像文件就是指烧录到ROM 中的bin 文件也称为image 文件以下用Image 文件来称呼它Image 文件包含了RO 和RW 数据之所以Image 文件不包含ZI 数据是因为ZI 数据都是0没必要包含只要程序运行之前将ZI 数据所在的区域一律清零即可包含进去反而浪费存储空间Q为什么Image 中必须包含RO 和RWA 因为RO 中的指令和常量以及RW 中初始化过的变量是不能像ZI 那样无中生有的ARM 程序的执行过程从以上两点可以知道烧录到ROM 中的image 文件与实际运行时的ARM 程序之间并不是完全一样的因此就有必要了解ARM 程序是如何从ROM 中的image到达实际运行状态的实际上RO 中的指令至少应该有这样的功能1 将RW 从ROM 中搬到RAM 中因为RW 是变量变量不能存在ROM 中2 将ZI 所在的RAM 区域全部清零因为ZI 区域并不在Image 中所以需要程序根据编译器给出的ZI 地址及大小来将相应得RAM 区域清零ZI 中也是变量同理变量不能存在ROM 中在程序运行的最初阶段RO 中的指令完成了这两项工作后 C 程序才能正常访问变量否则只能运行不含变量的代码说了上面的可能还是有些迷糊RORW 和ZI 到底是什么下面我将给出几个例子最直观的来说明RORWZI 在C 中是什么意思1 RO看下面两段程序他们之间差了一条语句这条语句就是声明一个字符常量因此按照我们之前说的他们之间应该只会在RO 数据中相差一个字节字符常量为1 字节Prog1includevoid main voidProg2includeconst char a 5 void main voidProg1 编译出来后的信息如下Code RO Data RW Data ZI Data Debug948 60 0 96 0 Grand TotalsTotal RO Size Code RO Data1008 098kBTotal RW Size RW Data ZI Data 96 009kBTotal ROM Size Code RO Data RW Data 1008098kBProg2 编译出来后的信息如下Code RO Data RW Data ZI Data Debug948 61 0 96 0Grand TotalsTotal RO Size Code RO Data 1009 099kBTotal RW Size RW Data ZI Data 96 009kBTotal ROM Size Code RO Data RW Data 1009 099kB以上两个程序编译出来后的信息可以看出Prog1 和Prog2 的RO 包含了Code 和RO Data 两类数据他们的唯一区别就是Prog2 的RO Data 比Prog1 多了1 个字节这正和之前的推测一致如果增加的是一条指令而不是一个常量则结果应该是Code 数据大小有差别2 RW同样再看两个程序他们之间只相差一个已初始化的变量按照之前所讲的已初始化的变量应该是算在RW 中的所以两个程序之间应该是RW 大小有区别Prog3includevoid main voidProg4includechar a 5 void main voidProg3 编译出来后的信息如下Code RO Data RW Data ZI DataDebug948 60 0 96 0 Grand TotalsTotal RO Size Code RO Data 1008 098kBTotal RW Size RW Data ZI Data 96009kBTotal ROM Size Code RO Data RW Data 1008098kBProg4 编译出来后的信息如下Code RO Data RW Data ZI Data Debug948 60 1 96 0 GrandTotalsTotal RO Size Code RO Data 1008 098kBTotal RW Size RW Data ZI Data 97 009kBTotal ROM Size Code RO Data RW Data 1009 099kB可以看出Prog3 和Prog4 之间确实只有RW Data 之间相差了1个字节这个字节正是被初始化过的一个字符型变量a所引起的3 ZI再看两个程序他们之间的差别是一个未初始化的变量a从之前的了解中应该可以推测这两个程序之间应该只有ZI 大小有差别Prog3includevoid main voidProg4includevoid main voidProg3 编译出来后的信息如下Code RO Data RW Data ZI Data Debug948 60 0 96 0 GrandTotal RO Size Code RO Data 1008 098kBTotal RW Size RW Data ZI Data 96 009kBTotal ROM Size Code RO Data RW Data 1008 098kBProg4 编译出来后的信息如下Code RO Data RW Data ZI Data Debug948 60 0 97 0 GrandTotalsTotal RO Size Code RO Data 1008 098kBTotal RW Size RW Data ZI Data 97009kBTotal ROM Size Code RO Data RW Data 1008098kB编译的结果完全符合推测只有ZI 数据相差了1 个字节这个字节正是未初始化的一个字符型变量a所引起的注意如果一个变量被初始化为0则该变量的处理方法与未初始化华变量一样放在ZI 区域即ARM C 程序中所有的未初始化变量都会被自动初始化为0总结1 C 中的指令以及常量被编译后是RO 类型数据2 C 中的未被初始化或初始化为0 的变量编译后是ZI 类型数据3 C 中的已被初始化成非0 值的变量编译后市RW 类型数据附程序的编译命令假定C 程序名为tstcarmcc -c -o tsto tstcarmlink -noremove -elf -nodebug -info totals -info sizes -map -list aamap-o tstelf tsto编译后的信息就在aamap 文件中ROM 主要指NAND FlashNor FlashRAM 主要指PSRAMSDRAMSRAMDDRAM继续学习中先把开发板自带一个例子做了些精简以免看得吓人就是这个让PORTD 上接的4 个LED 分别点亮开始研究代码int main voidInit_All_Periph看到这一行开始跟踪于是又看到了下面的内容void Init_All_Periph voidRCC_Configuration继续跟踪void RCC_Configuration voidSystemInit这行代码在system_stm32f10xc 中找到了void SystemInit voidReset the RCC clock configuration to the default reset state fordebug purposeSet HSION bitRCC- CR uint32_t 0x00000001Reset SW HPRE PPRE1 PPRE2 ADCPRE and MCO bits ifndef STM32F10X_CLRCC- CFGR uint32_t 0xF8FF0000elseRCC- CFGR uint32_t 0xF0FF0000endif STM32F10X_CLReset HSEON CSSON and PLLON bitsRCC- CR uint32_t 0xFEF6FFFFReset HSEBYP bitRCC- CR uint32_t 0xFFFBFFFFReset PLLSRC PLLXTPRE PLLMUL and USBPREOTGFSPRE bits RCC- CFGR uint32_t 0xFF80FFFFifndef STM32F10X_CLDisable all interrupts and clear pending bits RCC- CIR 0x009F0000elseReset PLL2ON and PLL3ON bitsRCC- CR uint32_t 0xEBFFFFFFDisable all interrupts and clear pending bits RCC- CIR 0x00FF0000Reset CFGR2 registerRCC- CFGR2 0x00000000endif STM32F10X_CLConfigure the System clock frequency HCLK PCLK2 and PCLK1 prescalersConfigure the Flash Latency cycles and enable prefetch bufferSetSysClock这一长串的又是什么如何来用呢看来偷懒是不成的了只能回过头去研究STM32 的时钟构成了相当的复杂系统的时钟可以有3 个来源内部时钟HSI外部时钟HSE或者PLL 锁相环模块的输出它们由RCC_CFGR 寄存器中的SW 来选择SW 10系统时钟切换由软件置1或清0来选择系统时钟源在从停止或待机模式中返回时或直接或间接作为系统时钟的HSE 出现故障时由硬件强制选择HSI 作为系统时钟如果时钟安全系统已经启动00HSI 作为系统时钟01HSE 作为系统时钟10PLL 输出作为系统时钟11不可用PLL 的输出直接送到USB 模块经过适当的分频后得到48M 的频率供USB 模块使用系统时钟的一路被直接送到I2S 模块另一路经过AHB 分频后送出送往各个系统其中直接送往SDIFMSCAHB 总线8 分频后作为系统定时器时钟经过APB1 分频分别控制PLK1定时器TIM2TIM7经过APB2 分频分别控制PLK2定时器TIM1TIM8再经分频控制ADC由此可知STM32F10x 芯片的时钟比之于51AVRPIC 等8 位机要复杂复多因此我们立足于对着芯片手册来解读程序力求知道这些程序代码如何使用为何这么样使用如果自己要改可以修改哪些部分以便自己使用时可以得心应手单步执行看一看哪些代码被执行了Reset the RCC clock configuration to the default reset state fordebug purposeSet HSION bitRCC- CR uint32_t 0x00000001这是RCC_CR 寄存器由图可见HSION 是其bit 0 位HSION内部高速时钟使能由软件置1或清零当从待机和停止模式返回或用作系统时钟的外部4-25MHz 时钟发生故障时该位由硬件置1来启动内部8MHz 的RC 振荡器当内部8MHz 时钟被直接或间接地用作或被选择将要作为系统时钟时该位不能被清零0内部8MHz 时钟关闭1内部8MHz 时钟开启Reset SW HPRE PPRE1 PPRE2 ADCPRE and MCO bitsifndef STM32F10X_CLRCC- CFGR uint32_t 0xF8FF0000这是RCC_CFGR 寄存器该行程序清零了MC0[20]这三位和ADCPRE[10]ppre2[20]PPRE1 〔20〕HPRE 〔30〕SWS 〔10〕和SW 〔10〕这16 位MCO 微控制器时钟输出由软件置1或清零0xx没有时钟输出100系统时钟 SYSCLK 输出101内部8MHz 的RC 振荡器时钟输出110外部4-25MHz 振荡器时钟输出111PLL 时钟2 分频后输出Reset HSEON CSSON and PLLON bitsRCC- CR uint32_t 0xFEF6FFFF清零了PLLONHSEBYPHSERDY 这3 位Reset HSEBYP bitRCC- CR uint32_t 0xFFFBFFFF清零了HSEBYP 位为什么不一次写HSEBYP外部高速时钟旁路在调试模式下由软件置1或清零来旁路外部晶体振荡器只有在外部4-25MHz 振荡器关闭的情况下才能写入该位0外部4-25MHz 振荡器没有旁路1外部4-25MHz 外部晶体振荡器被旁路所以要先清HSEON 位再清该位Reset PLLSRC PLLXTPRE PLLMUL and USBPREOTGFSPRE bitsRCC- CFGR uint32_t 0xFF80FFFF清零了USBPREPLLMULPLLXTPRPLLSRC 共7 位Disable all interrupts and clear pending bitsRCC- CIR 0x009F0000这个暂不解读SetSysClock跟踪进入该函数可见一连串的条件编译单步运行执行的是elif defined SYSCLK_FREQ_72MHzSetSysClockTo72为何执行该行呢找到SYSCLK_PREQ_的相关定义如下图所示这样就得到了我们所要的一个结论如果要更改系统工作频率只需要在这里更改就可以了可以继续跟踪进入这个函数来观察如何将工作频率设定为72MHz 的static void SetSysClockTo72 void。
STM32学习笔记

STM32学习笔记 linlifeng 2011/01/1300 STM32学习笔记-基本硬件 (2)01 STM32学习笔记-编译 (3)02 STM32学习笔记-FLASH/IAP (8)03 STM32学习笔记-CAN (9)04 STM32学习笔记-PVD (14)05 STM32学习笔记-PWM (15)06 STM32学习笔记-ADC (16)07 STM32学习笔记-RCC (17)08 STM32学习笔记-BOOT (18)90 STM32学习笔记-关于库的杂谈 (21)Q1:static型变量和函数有什么区别? (25)00 STM32学习笔记-基本硬件拉电流/灌电流:最大可以输出8mA,灌入20mA,但要保证所有进入芯片VDD的电流不能超过150mA,同样所有从VSS流出的电流也不能超过150mA。
复位没用电池供备份寄存器的话,若复位,不管是内部复位源还是外部复位源,所有SRAM区全部清零。
所以寄希望于内部看门狗复位后全局变量值保持不变是比较困难的。
如果非要保持不变呢?困难是有,解决起来也是会者不难,赵MM教我的方法,是在TARGET设置里,在RAM区分配几个字节令其值不复位(noint),然后将要保持不变的全局变量放在这写RAM区里就OK了,注意这样做之后上电后这些全局变量的初值就有可能不再是0而是随机值了。
USART/thread-3632263-1-1.html01 STM32学习笔记-编译要了解RO,RW和ZI需要首先了解以下知识:ARM程序的组成此处所说的“ARM程序”是指在ARM系统中正在执行的程序,而非保存在ROM中的bin映像(image)文件,这一点清注意区别。
一个ARM程序包含3部分:RO,RW和ZIRO是程序中的指令和常量RW是程序中的已初始化变量ZI是程序中的未初始化的变量由以上3点说明可以理解为:RO就是readonly,RW就是read/write,ZI就是zeroARM映像文件的组成所谓ARM映像文件就是指烧录到ROM中的bin文件,也称为image文件。
STM32学习笔记

STM32学习笔记从51开始,单片机玩了很长时间了,有51,PIC,AVR等等,早就想跟潮流玩玩ARM,但一直没有开始,原因-----不知道玩了ARM可以做什么(对我自己而言)。
如果为学习而学习,肯定学不好。
然后cortex-m3出来了,据说,这东西可以替代单片机,于是马上开始关注。
也在第一时间开始学习,可惜一开始就有点站错了队,选错了型(仍是对我自己而言)。
我希望这种芯片应该是满大街都是,随便哪里都可以买得到,但我选的第一种显然做不到。
为此,大概浪费了一年多时间吧,现在,回到对我来说是正确的道路上来啦,边学边写点东西。
这里写的是我的学习的过程,显然,很多时候会是不全面的,不系统的,感悟式的,甚至有时会是错误的,有些做法会是不专业的。
那么,为什么我还要写呢?这是一个有趣的问题,它甚至涉及到博客为什么要存在的问题。
显然,博客里面的写的东西,其正确性、权威性大多没法和书比,可为什么博客会存在呢?理由很多,我非专家,只说我的感慨。
我们读武侠小说,总会有一些创出独门功夫的宗师,功夫极高,然后他的弟子则基本上无法超越他。
我在想,这位宗师在创造他自己的独门功夫时,必然会有很多的次的曲折、弯路、甚至失败,会浪费他的很多时间,而他教给弟子时,则已去掉了这些曲折和弯路,当然更不会把失败教给弟子,按理说,效率应该更高,可是没用,弟子大都不如师。
为什么呢?也许知识本身并不是最重要的,获取知识的过程才是最重要的?也许所谓的知识,并不仅仅是一条条的结论,而是附带着很多说不清道不明的东西?如植物的根,一条主根上必带有大量的小小的触须?闲话多了些,就权当前言了。
下面准备开始。
一、条件的准备我的习惯,第一步是先搭建一个学习的平台。
原来学51,PIC,AVR时,都是想方设法自己做些工具,实验板之类,现在人懒了,直接购买成品了。
硬件电路板:火牛板软件:有keil和iar可供选择。
网上的口水仗不少,我选keil,理由很简单,这个我熟。
STM32---学习笔记

/*****************************DATE : 8/20/2010*************************************************************************************************************#include "stm32f10x_lib.h"#include "TFT.h"#define ADC1_DR_Address ((u32)0x4001244C) //ADC1数据寄存器地址ADC_InitTypeDef ADC_InitStructure;DMA_InitTypeDef DMA_InitStructure;vu16 ADCConvertedValue;void RCC_Configuration(void);void GPIO_Configuration(void);void NVIC_Configuration(void);void Num2String(unsigned int Num,unsigned char *Ptr);int main(void){unsigned char AD_CharData[4];//volatile unsigned long data;/* System clocks configuration ---------------------------------------------*/RCC_Configuration();/* NVIC configuration ------------------------------------------------------*/NVIC_Configuration();/* GPIO configuration ------------------------------------------------------*/GPIO_Configuration();TFT_Init();/* DMA1 channel1 configuration ----------------------------------------------*/DMA_DeInit(DMA1_Channel1); //选择通道1DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;//ADC1的地址为DMA 的外设基地址DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADCConvertedValue;//内存基地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外设作为数据传输的来源DMA_InitStructure.DMA_BufferSize = 1; //DMA缓存大小为1个数据单位DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址寄存器不变DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; //内存地址寄存器不变DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据宽度为16位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //内存数据宽度为16位DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA工作在循环缓存模式DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道1拥有高优先级DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //禁止DMA通道的内存到内存传输,因为这里是外设到内存的传输DMA_Init(DMA1_Channel1, &DMA_InitStructure);/* Enable DMA1 channel1 */DMA_Cmd(DMA1_Channel1, ENABLE);/* ADC1 configuration ------------------------------------------------------*/ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC1工作在独立模式ADC_InitStructure.ADC_ScanConvMode = DISABLE;ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//工作在连续转换模式ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//由软件来触发转换启动ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;// ADC数据右对齐ADC_InitStructure.ADC_NbrOfChannel = 1;//顺序进行规则转换的ADC通道数目为1 ADC_Init(ADC1, &ADC_InitStructure);//为了能够正确配置每一个ADC通道,在调用ADC_Init()之后,必须调用ADC_ChannelConfig()//来配置每个所使用通道的转换次序和采样时间/* ADC1 regular channel8 configuration 采样时间为55.5周期*/ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_55Cycles5);/* Enable ADC1 DMA */ADC_DMACmd(ADC1, ENABLE);/* Enable ADC1 */ADC_Cmd(ADC1, ENABLE);/* Enable ADC1 reset calibaration register 复位校准寄存器*/ADC_ResetCalibration(ADC1);/* Check the end of ADC1 reset calibration register */while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位完成/* Start ADC1 calibaration 开始校准*/ADC_StartCalibration(ADC1);/* Check the end of ADC1 calibration */while(ADC_GetCalibrationStatus(ADC1));//等待校准完成/* Start ADC1 Software Conversion */ADC_SoftwareStartConvCmd(ADC1, ENABLE); //开始转换//data = ADCConvertedValue*3.3;//data = data/4096;while (1){Num2String(ADCConvertedValue,AD_CharData);Display_RGBw_16bit(0x00,0x00);Display_Ascii_16bit(60,160,"AIN8 V ALUE:",3,0);Display_Ascii_16bit(148,160,AD_CharData,3,0);}}/****************************************************************************** ** Function Name : RCC_Configuration* Description : Configures the different system clocks.* Input : None* Output : None* Return : None******************************************************************************* /void RCC_Configuration(void){ErrorStatus HSEStartUpStatus;/* RCC system reset(for debug purpose) */RCC_DeInit();/* Enable HSE */RCC_HSEConfig(RCC_HSE_ON);/* Wait till HSE is ready */HSEStartUpStatus = RCC_WaitForHSEStartUp();if(HSEStartUpStatus == SUCCESS){/* Enable Prefetch Buffer */FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);/* Flash 2 wait state */FLASH_SetLatency(FLASH_Latency_2);/* HCLK = SYSCLK */RCC_HCLKConfig(RCC_SYSCLK_Div1);/* PCLK2 = HCLK */RCC_PCLK2Config(RCC_HCLK_Div1);/* PCLK1 = HCLK/2 */RCC_PCLK1Config(RCC_HCLK_Div2);/* ADCCLK = PCLK2/4 */RCC_ADCCLKConfig(RCC_PCLK2_Div4);/* PLLCLK = 8MHz * 7 = 56 MHz */RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7);/* Enable PLL */RCC_PLLCmd(ENABLE);/* Wait till PLL is ready */while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}/* Select PLL as system clock source */RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);/* Wait till PLL is used as system clock source */while(RCC_GetSYSCLKSource() != 0x08){}}/* Enable peripheral clocks --------------------------------------------------*//* Enable DMA1 clock */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE, ENABLE);}/****************************************************************************** ** Function Name : GPIO_Configuration* Description : Configures the different GPIO ports.* Input : None* Output : None* Return : None******************************************************************************* /void GPIO_Configuration(void){GPIO_InitTypeDef GPIO_InitStructure;/* Configure PB.0 (ADC Channel8) as analog input -------------------------*/GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOB, &GPIO_InitStructure);/* Configure PD.11--PC.15 as Output push-pull */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_10 | GPIO_Pin_9 | GPIO_Pin_8 |GPIO_Pin_7 ;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOD, &GPIO_InitStructure);/* Configure PE.00 -- PE.15 as Output push-pull */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOE, &GPIO_InitStructure);}//int整型数转换成字符串void Num2String(unsigned int Num,unsigned char *Ptr){unsigned char instr[4];unsigned char i=4;unsigned char k;do{instr[--i] = Num%10+'0';Num/=10;}while(Num!=0);for(k=i;k<4;k++){*Ptr++=instr[k];}*Ptr = '\0';}/****************************************************************************** ** Function Name : NVIC_Configuration* Description : Configures Vector Table base location.* Input : None* Output : None* Return : None******************************************************************************* /void NVIC_Configuration(void){#ifdef VECT_TAB_RAM/* Set the Vector Table base location at 0x20000000 */NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);#else /* VECT_TAB_FLASH *//* Set the Vector Table base location at 0x08000000 */NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);#endif}#include "stm32f10x_lib.h"void RCC_Configuration(void);void NVIC_Configuration(void);void USART_Config(void);void USART2_Puts(char * str); //输出字符串void USART2_Putc(char c); //输出一个字符unsigned char USART2_ReceiveChar(void); //接收一个字符同时作为是一个函数声明int main(void){RCC_Configuration();NVIC_Configuration();USART_Config();while (1){USART2_Putc(USART2_ReceiveChar());USART2_Puts(USART2_ReceiveChar());}}/****************************************************************************** ** 函数名: RCC_Configuration* 功能: 时钟配置* 输入: 无* 输出: 无* 返回: 无******************************************************************************* /void RCC_Configuration(void){ErrorStatus HSEStartUpStatus;RCC_DeInit();RCC_HSEConfig(RCC_HSE_ON);HSEStartUpStatus = RCC_WaitForHSEStartUp();if(HSEStartUpStatus == SUCCESS){FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);FLASH_SetLatency(FLASH_Latency_2);RCC_HCLKConfig(RCC_SYSCLK_Div1);RCC_PCLK2Config(RCC_HCLK_Div1);RCC_PCLK1Config(RCC_HCLK_Div2);RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);RCC_PLLCmd(ENABLE);while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);while(RCC_GetSYSCLKSource() != 0x08){}}}void USART_Config(void){GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA, &GPIO_InitStructure);USART_ART_BaudRate = 9600;USART_ART_WordLength = USART_WordLength_8b;USART_ART_StopBits = USART_StopBits_1;USART_ART_Parity = USART_Parity_No ;USART_ART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_ART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_Init(USART2, &USART_InitStructure);USART_Cmd(USART2, ENABLE);}void USART2_Putc(char c){USART_SendData(USART2, c);while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);}void USART2_Puts(char * str){while(*str){USART_SendData(USART2, *str++);while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);}}unsigned char USART2_ReceiveChar(void){while(USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == RESET);return(USART_ReceiveData(USART2));}/****************************************************************************** ** 函数名: NVIC_Configuration* 功能: 中断配置* 输入: 无* 输出: 无* 返回: 无******************************************************************************* /void NVIC_Configuration(void){#ifdef VECT_TAB_RAMNVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);#elseNVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);#endif}。
学习STM32笔记汇总

学习STM32笔记汇总STM32F207学习笔记1、使用篇 (1)1、1标准外设库的简介 (1)1.2标准外设库中一些文件的作用 (2)1.3开发拾遗 (2)2、STM32技术概述 (3)2.1 一些概述 (3)2.2 STM32的最小系统 (3)2.3 一些IO (4)2.31 GPIO与AFIO (4)2.32 RCC 复位与时钟控制 (5)2.33 中断与事件控制 (6)2.34总线结构与存储器: (6)2.35 定时器(是定时还是计数只取决于时钟源) (6)1、使用篇1、1标准外设库的简介在嵌入式设计中,硬件成本不断降低,而软件成本大幅升高,随着新型内核的不断出现,软件底层设计的复杂性和移植的困难度在不断增加,ARM公司意识到这个问题后,联合芯片提供商,为软件人员提供标准的应用程序接口,而CMSIS就是为CONTEX-M3内核提供的。
这些通用的API接口来访问CORTEX 内核以及一些专用外设,以减少更换芯片以及开发工具等移植工作所带来的金钱以及时间上的消耗。
只要都是基于M3的芯片,代码均是可以复用的。
CMSIS 包含了CORESUPPORT和DECICESUPPORT。
即ARM负责的东西和芯片厂商如ST负责的。
其中ARM提供了core_m3.c和.h。
定义一些CORTEX-M处理器内部的一些寄存器地址以及功能函数。
芯片商提供的启动代码、初始化函数、系统头文件。
为了推广了STM32系列的微处理器芯片,意法半导体可谓是煞费苦心!不光提供了CMSIS要求内容,还提供了各个模块的标准库函数.,包含了所有外设的驱动函数,覆盖每一种外设的所有功能。
可以让程序员将更多的精力放在应用开发,加快上市时间,用标准的ANSI-C编写不受开发环境的影响。
这一系列的辅助文件以固件库(标准外设库)来提供。
那手头上的版本STM32F2xx_StdPeriph_Lib_V1.1.0来说,有三部分构成:1、library:标准外设库的主要内容,由两部分构成①CMSIS(1)ARM公司提供的内核访问函数等。
手把手教你STM32笔记

STM32F1031、IO口处理IO口包含7个寄存器配置寄存器两个:CRL(32),CRH(32)数据寄存器两个:IDR(32),ODR(32),但是他们只用了16位置位复位寄存器:BSRR(32)复位寄存器:BRR(16)锁存寄存器:LCKR(32)常用的有前面四个:其中前面两个是用来设置的,后面两个是用来操作的。
每个IO口占用四位进行设置(低两位是MODE,高两位是CNF),每组16个,总共需要64个位设置,分别从CRL低位开始,到CRH 的高位结束。
每个IO口四位二进制的常用配置:模拟输入模式(ADC):0x0;推挽输出模式(输出口50MHz):0x3;上/下拉输入模式(输入口用):0x8;复用输出(第二供能):0xB;STM32F407学习笔记1、系统时钟的设置:Stm32_Clock_Init(168,4,2,7);参数分别是:PLLN,PLLM,PLLP,PLLQHSE分频PLLM之后为VCO的输入,一般VCO的输入要求为1~2MHz,一般建议取为2MHz,防止PLL抖动。
VCO输出是输入的PLLN倍频,SYSCLK在去PLL输出时,SYSCLK = PLL=HSE/PLLM*PLLN/PLLP而PLLQ是为48MHz时钟配置用的,CLK48= HSE/PLLM*PLLN/PLLQ所以要设置系统时钟为168MHz时候推荐的参数取值为SYSCLK = PLL=HSE/PLLM*PLLN/PLLP =8/4*168/2=168MHzCLK48= HSE/PLLM*PLLN/PLLQ=8/4*168/7=48MHz2、延时函数设置:delay_init(168);延时函数参数为系统时钟SYSCLK初始化后就可以调用延时函数:delay_ms(ms);参数不能大于65536,因为参数是16位数delay_us(us);参数不能大于7989153、普通IO的使用a.首先是使能时钟RCC->AHB1ENR|=1<<5;在该寄存器相应的位置1即可b.IO口模式设置:GPIO_Set(GPIOF,PIN9|PIN10,GPIO_MODE_OUT,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD _PU);参数分别是:GPIOx,PIN9|PIN10(具体对应的口,可以使用与的关系)因为每种占一位#define PIN0 1<<0#define PIN1 1<<1#define PIN2 1<<2#define PIN3 1<<3#define PIN4 1<<4#define PIN5 1<<5#define PIN6 1<<6#define PIN7 1<<7#define PIN8 1<<8#define PIN9 1<<9#define PIN10 1<<10#define PIN11 1<<11#define PIN12 1<<12#define PIN13 1<<13#define PIN14 1<<14#define PIN15 1<<15Mode:四种,各个模式只能设置一种#define GPIO_MODE_IN 0 //普通输入模式#define GPIO_MODE_OUT 1 //普通输出模式#define GPIO_MODE_AF 2 //AF功能模式#define GPIO_MODE_AIN 3 //模拟输入模式输出推挽或者开漏选择:#define GPIO_OTYPE_PP 0 //推挽输出#define GPIO_OTYPE_OD 1 //开漏输出推挽输出可输出强的高、低电平,用于连接数字器件开漏输出相当于三极管的集电极,电流型驱动,只可以输出强的低电平,高电平需外拉。
STM32学习笔记小结

STM32学习笔记目录STM32学习笔记 (1)一、入门 (2)目标->实战项目 (2)STM32学习方法 (3)ARM简介 (4)二、外设功能模块 (5)GPIO原理与工作模式 (5)串行通信 (6)硬件下载与调试 (6)Cortex-M3复用功能(AF)和重映射功能 (6)Systick的使用 (7)通用定时器 (7)SPI与数码管 (7)I2C通信 (8)NVIC中断 (8)PWM基础 (9)RCC内部结构与原理 (9)ADC模数转换 (10)内部温度传感器 (10)窗口看门狗 (10)USB应用 (11)三、问题 (11)在线调试 (12)一、入门STM32系列基于专为要求高性能、低成本、低功耗的嵌入式应用专门设计的ARM Cortex-M内核,主要包括STM32F101“基本型”系列、STM32F103“增强型”系列、STM32F105、STM32F107“互联型”系列。
STM32微控制器满足嵌入式开发低功耗和高性能的要求,并且拥有简单易上手的固件函数库,避免了传统ARM单片机开发操作寄存器的模式,所以十分受欢迎,应用广泛。
作者只学过一些51单片机的基础,就直接上手STM32,边学边用。
该篇笔记也是随意的记录一下,要想系统的学习一下,个人认为资料手册(data sheet)、参考手册(Reference Manual)和用户手册(固件函数库)三个文档再有开发板实际操作,完全足够。
熟练掌握以上内容,触类旁通,成为STM32开发的高手指日可待。
目标->实战项目STM32学习方法开发环境(MDK/IAR)寄存器or固件库软件仿真&开发板硬件学习难度建立不受库版本限制的工程项目:1.准备好文件(Startup Code、Lib、User)2.建立工程不添加Startup Code3.工程管理添加需要的库文件、自定义文件4.编译链接ARM简介ARM7衍生出全新的Cortex架构,三管齐下:Cortex-A:高性能应用处理器。
stm32学习笔记

STM32学前班教程之一:为什么是它经过几天的学习,基本掌握了STM32的调试环境和一些基本知识。
想拿出来与大家共享,笨教程本着最大限度简化删减STM32入门的过程的思想,会把我的整个入门前的工作推荐给大家。
就算是给网上的众多教程、笔记的一种补充吧,所以叫学前班教程。
其中涉及产品一律隐去来源和品牌,以防广告之嫌。
全部汉字内容为个人笔记。
所有相关参考资料也全部列出。
教程会分几篇,因为太长啦。
今天先来说说为什么是它——我选择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、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
系统时钟 SYSCLK 最大频率为 72MHz,它是供 STM32 中绝大部分部件工作的时钟源。 系统时钟可由 PLL、HSI 或者 HSE 提供输出,并且它通过 AHB 分频器分频后送给各模 块使用,AHB 分频器可选择 1、2、4、8、16、64、128、256、512 分频。其中 AH B 分频器输出的时钟送给 5 大模块使用:①、送给 AHB 总线、内核、内存和 DMA 使用 的 HCLK 时钟。 ②、分频后送给 STM32 芯片的系统定时器时钟(Systick=Sysclk/8=9Mhz) ③、直接送给 Cortex 的自由运行时钟(free running clock)FCLK。【ARMJISHU 注:FCL K 为处理器的自由振荡的处理器时钟,用来采样中断和为调试模块计时。在处理器休眠时, 通过 FCLK 保证可以采样到中断和跟踪休眠事件。 Cortex-M3 内核的“自由运行时钟(fre e running clock)”FCLK。“自由”表现在它不来自系统时钟 HCLK,因此在系统时钟停 止时 FCLK 也继续运行。FCLK 和 HCLK 互相同步。FCLK 是一个自由振荡的 HCLK。FCL K 和 HCLK 应该互相平衡,保证进入 Cortex-M3 时的延迟相同。】④、送给 APB1 分频 器。APB1 分频器可选择 1、2、4、8、16 分频,其输出一路供 APB1 外设使用(PCLK1, 最大频率 36MHz),另一路送给定时器(Timer)2、3、4 倍频器使用。该倍频器可选择 1 或 者 2 倍频,时钟输出供定时器 2、3、4 使用。 ⑤、送给 APB2 分频器。APB2 分频器可选择 1、2、4、8、16 分频, 其输出一路供 APB 2 外设使用(PCLK2,最大频率 72MHz),另一路送给定时器(Timer)1 倍频器使用。该倍频
学习 stm32 的笔记了,写的比较乱,不过比较详细,有兴趣的朋友一起学习啦,共同进步
流水灯
#include "led.h" #include "delay.h" #include "rcc.h" int main(void) {
int i; RCC_Configuration(); delay_init(); LED_Init(); while(1) { GPIO_SetBits(GPIOB,GPIO_Pin_5); GPIO_SetBits(GPIOD,GPIO_Pin_6); GPIO_SetBits(GPIOD,GPIO_Pin_3); delay_ms(1000); delay_ms(1000); } }
在以上的时钟输出中,有很多是带使能控制的,例如 AHB 总线时钟、内核时钟、 各种 APB1 外设、APB2 外设等等。当需要使用某模块时,记得一定要先使能对应的时 钟。
需要注意的是定时器的倍频器,当 APB 的分频为 1 时,它的倍频值为 1,否则它 的倍频值就为 2。
连接在 APB1(低速外设)上的设备有:电源接口、备份接口、CAN、USB、I2C1、I 2C2、UART2、UART3、SPI2、窗口看门狗、Timer2、Timer3、Timer4。
注意:USB 模块虽然需要一个单独的 48MHz 时钟信号,但它应该不是供 USB 模 块工作的时钟,而只是提供给串行接口引擎(SIE)使用的时钟。USB 模块工作的时钟应 该是由 APB1 提供的。
连接在 APB2(高速外设)上的设备有:UART1、SPI1、Timer1、 ADC1、ADC2、所有普通 IO 口(PA~PE)、第二功能 IO 口。
Systick 的时钟频率为 f=sysclk/8Hz,则周期 T=8/sysclk S, 一次计数所花的时间 ms=8/sysclk/1000,systick 是 24 位计数器,从 0 记到 0xffffff 溢出了, 则一次延时时间不能超过:8/sysclk/1000Xffffff=1864.135ms,就是这样算的
GPIO_SetBits(GPIOD,GPIO_Pin_6); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_Init(GPIOD, &GPIO_InitStructure); GPIO_SetBits(GPIOD,GPIO_Pin_3); }
GPIOB 的地址=0x0C00+0x10000+0x40000000=0x40010C00
}
#include "rcc.h" void RCC_Configuration(void) {
SystemInit();//设置系统时钟为 72MHZ }
时钟控制寄存器(RCC_CR) 偏移地址: 0x00 复位值: 0x000 XX83(10000011) ,X 代表未定义
位 7:3
由软件写入来调整内部高速时钟,它们被叠加在 HSICAL[5:0]数值上。 这些位在 HSICAL[7:0]的基础上,让用户可以输入一个调整数值,根据电压和温度的变化调整 内部 HSI RC 振荡器的频率。 默认数值为 16(10000),可以把 HSI 调整到 8MHz±1%;每步 HSICAL 的变化调整约 40kHz。 位 2 保留,始终读为 0。 HSIRDY:内部高速时钟就绪标志(Internal high-speed clock ready flag) 位 1 由硬件置’1’来指示内部 8MHz 振荡器已经稳定。在 HSION 位清零后,该位需要 6 个内部 8MHz 振 荡器周期清零。 0:内部 8MHz 振荡器没有就绪; 1:内部 8MHz 振荡器就绪。 HSION:内部高速时钟使能(Internal high-speed clock enable) 位 0 由软件置’1’或清零。 当从待机和停止模式返回或用作系统时钟的外部 4-16MHz 振荡器发生故障时,该位由硬件置’1’ 来启动内部 8MHz 的 RC 振荡器。当内部 8MHz 振荡器被直接或间接地用作或被选择将要作为系 统时钟时,该位不能被清零。 0:内部 8MHz 振荡器关闭; 1:内部 8MHz 振荡器开启。
总体上掌握 STM32 的时钟系统。
static u8 fac_us=0;//us 延时倍乘数 static u16 fac_ms=0;//ms 延时倍乘数 //初始化延迟函数 //SYSTICK 的时钟固定为 HCLK 时钟的 1/8
//SYSCLK:系统时钟 void delay_init() {
器可选择 1 或者 2 倍频,时钟输出 供定时器 1 使用。另外,APB2 分频器还有一路输出供 ADC 分频器使用,分频后送给 ADC 模块使用。ADC 分频器可选择为 2、4、6、8 分频。
以上提到 3 种时钟 Fclk、Hclk 和 Pclk,简单解释如下:Fclk 为供给 CPU 内核的 时钟信号,我们所说的 cpu 主频为 XXXXMHz,就是指的这个时钟信号,相应的,1/ Fclk 即为 cpu 时钟周期;Hclk 为优秀的高性能总线(AHB bus peripherals)供给 时钟信号(AHB 为 advanced high-performance bus);HCLK :AHB 总线时钟, 由系统时钟 SYSCLK 分频得到,一般不分频,等于系统时钟,HCLK 是高速外设时钟,是 给外部设备的,比如内存,flash。Pclk 为优秀的高性能外设总线(APB bus periphe rals)供给时钟信号(其中 APB 为 advanced peripherals bus)。
{
u32 temp;
SysTick->LOAD=(u32)nms*fac_ms;//时间加载(SysTick->LOAD 为 24bit)
SysTick->VAL =0x00;
//清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;
//开始倒数
do
{
temp=SysTick->CTRL;
//延时 nms
//注意 nmsAD 为 24 位寄存器,所以,最大延时为:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK 单位为 Hz,nms 单位为 ms
//对 72M 条件下,nms<=1864
void delay_ms(u16 nms)
⑤PLL 为锁相环倍频输出,其时钟输入源可选择为 HSI/2、HSE 或者 HSE/2。倍频可选择为 2~16 倍,但是其输出频率最大不得超过 72MHz。
其中 40kHz 的 LSI(低速内部时钟)供独立看门狗 IWDG 使用,另外它还可以被选择
为实时时钟 RTC 的时钟源。另外,实时时钟 RTC 的时钟源还可以选 择 LSE(低速外部
在 STM32 中,有五个时钟源,为 HSI、HSE、LSI、LSE、PLL。
①HSI 是高速内部时钟,RC 振荡器,频率为 8MHz。
②HSE 是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为 4MHz~16MHz。
③LSI 是低速内部时钟,RC 振荡器,频率为 40kHz。
④LSE 是低速外部时钟,接频率为 32.768kHz 的石英晶体。
}
while(temp&0x01&&!(temp&(1<<16)));//等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;
//关闭计数器 ~:按位取反运算符
SysTick->VAL =0X00;
//清空计数器
}
SysTick->CTRL 的各位定义如图 5.1.1.1 所示: