|
一、教程1 STM32学习教程 1、 一共24个库,不可能都学,都学也没用。按照我的工作需求必须学的有16个,这16个也不是全学。主要学习来源是各种例程代码、“固件函数库用户手册”和“参考手册”。4 _( d7 t$ {0 l ' X4 A) N4 O$ z7 }0 ]( z5 J" ?" Y具体学习方法是通读不同来源的程序,在程序中找到相关的函数库的应用,然后再阅读相关文档,有条件的实验。对于内容的选择方面,根据入门内容和未来应用,将所涉及的范围精简到最低,但是对所选择的部分的学习则力求明确。以下是我按照自己的需求对程序库函数排列的学习顺序: a) 绝大部分程序都要涉及到的库——flash,lib,nvic,rcc,只学基础的跟最简单应用相关必用的部分,其他部分后期再返回头学。 b) 各种程序通用但不必用的库——exti,MDA,systic,只通读理解其作用。 c) DEMO板拥有的外设库——gpio,usart,编写代码实验。 d) 未来需要用到的外设的库——tim,tim1,adc,i2c,spi,先理解等待有条件后实验。% `+ P/ ]7 @$ I: H/ @% y' | B e) 开发可靠性相关库——bkp,iwdg,wwdg,pwr,参考其他例程的做法。' \: j y$ U1 J3 p& H f) 其他,根据兴趣来学。 STM32学前班教程之六:这些代码大家都用得到 注:下面是一些常用的代码,网上很多但是大多注释不全。高手看没问题,对于我们这些新手就费劲了……所以我把这些代码集中,进行了逐句注释,希望对新手们有价值。9 J, F/ }6 u* c6 j0 ?" x y( M2 P ! K8 b p q7 P2 ?1、 阅读flash: 芯片内部存储器flash操作函数 我的理解——对芯片内部flash进行操作的函数,包括读取,状态,擦除,写入等等,可以允许程序去操作flash上的数据。. d; e1 L3 d! o6 U 基础应用1,FLASH时序延迟几个周期,等待总线同步操作。推荐按照单片机系统运行频率,0—24MHz时,取Latency=0;24—48MHz时,取Latency=1;48~72MHz时,取Latency=2。所有程序中必须的) _% @9 U6 c. ] 用法:FLASH_SetLatency(FLASH_Latency_2);7 y4 Y. W# _7 L/ I+ C: r+ u 位置:RCC初始化子函数里面,时钟起振之后。 基础应用2,开启FLASH预读缓冲功能,加速FLASH的读取。所有程序中必须的 用法:FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);9 l8 J9 }6 ~# ]/ L+ z 位置:RCC初始化子函数里面,时钟起振之后。( P: m- |' _/ t7 L7 B& p: K; h 3、阅读lib:调试所有外设初始化的函数。 我的理解——不理解,也不需要理解。只要知道所有外设在调试的时候,EWRAM需要从这个函数里面获得调试所需信息的地址或者指针之类的信息。 基础应用1,只有一个函数debug。所有程序中必须的。 用法: #ifdef DEBUG debug();# ~6 y. L5 P- z! z #endif! P f7 U, ]* N% s% d 位置:main函数开头,声明变量之后。/ W, D$ j4 v" x/ W 4、阅读nvic:系统中断管理。 我的理解——管理系统内部的中断,负责打开和关闭中断。$ I) l! R$ ~# g; L2 f: o 基础应用1,中断的初始化函数,包括设置中断向量表位置,和开启所需的中断两部分。所有程序中必须的。* T7 h+ y0 B8 N! G7 O# e0 W/ S9 g 用法: void NVIC_Configuration(void)/ G. \' g, F! j; t" E/ }1 ] { NVIC_InitTypeDef NVIC_InitStructure; //中断管理恢复默认参数 #ifdef VECT_TAB_RAM //如C/C++Compiler\Preprocessor\Defined symbols中的定义了VECT_TAB_RAM(见程序库更改内容的表格) NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); //则在RAM调试 #else //如果没有定义VECT_TAB_RAM9 B2 S4 g& \& I5 g7 A8 w' T1 g NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);//则在Flash里调试 #endif //以下为中断的开启过程,不是所有程序必须的。 //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); $ b Z5 X: V4 f) v1 s6 H //设置NVIC优先级分组,方式。 //注:一共16个优先级,分为抢占式和响应式。两种优先级所占的数量由此代码确定,NVIC_PriorityGroup_x可以是0、1、2、3、4,分别代表抢占优先级有1、2、4、8、16个和响应优先级有16、8、4、2、1个。规定两种优先级的数量后,所有的中断级别必须在其中选择,抢占级别高的会打断其他中断优先执行,而响应级别高的会在其他中断执行完优先执行。 //NVIC_InitStructure.NVIC_IRQChannel = 中断通道名; //开中断,中断名称见函数库+ i7 i) X; l. m" M- ] //NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级 //NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应优先级: w' i. u4 o/ z T8 |: {: P //NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //启动此通道的中断' g7 X& Z* A+ T //NVIC_Init(&NVIC_InitStructure); //中断初始化- X, C1 ]9 x% t8 A, u9 E } 5、阅读rcc:单片机时钟管理。4 e. N/ G) N5 Y6 F8 ~# c 我的理解——管理外部、内部和外设的时钟,设置、打开和关闭这些时钟。7 H8 V' J/ ]6 b, d$ W 基础应用1:时钟的初始化函数过程—— 用法:void RCC_Configuration(void) //时钟初始化函数6 K* }3 I+ X, U9 K ? {; }/ N4 G! q8 q: ^7 E! \ ErrorStatus HSEStartUpStatus; //等待时钟的稳定+ H: Y/ \* [3 j' K6 O RCC_DeInit(); //将时钟重置为缺省值 RCC_HSEConfig(RCC_HSE_ON); //设置外部晶振 q) |! r* h0 ^& I5 z# R HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待外部晶振就绪1 |9 M$ W/ }, @: C+ m1 R( R1 ]# s( ? if (HSEStartUpStatus == SUCCESS) { FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);//使能预取缓存 FLASH_SetLatency(FLASH_Latency_2); //flash操作的延时 RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB使用系统时钟 RCC_PCLK2Config(RCC_HCLK_Div2); //APB2(高速)为HCLK的一半 RCC_PCLK1Config(RCC_HCLK_Div2); //APB1(低速)为HCLK的一半 //注:AHB主要负责外部存储器时钟。APB2负责AD,I/O,高级TIM,串口1。APB1负责DA,USB,SPI,I2C,CAN,串口2345,普通TIM。 0 q" P/ B8 @% T# t. y RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLLCLK = 8MHz * 9 = 72 MH //设置PLL时钟源及倍频系数 & b6 s" X2 K! j( C9 B+ p RCC_PLLCmd(ENABLE); //启动PLL5 R+ W$ g+ W6 R# W $ g O0 p; \; ]) n9 Fwhile (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {} //等待PLL启动 4 |" d3 ?2 S9 q4 A1 I4 W2 F/ i& rRCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //将PLL设置为系统时钟源 while (RCC_GetSYSCLKSource() != 0x08) ; M% A4 H% A2 l/ {5 \{} //将PLL返回,并作为系统时钟源 ( v" P9 @& q5 \1 |} % h, o7 t. J8 o//RCC_AHBPeriphClockCmd(ABP2设备1 | ABP2设备2 |, ENABLE); //启动AHP设备 //RCC_APB2PeriphClockCmd(ABP2设备1 | ABP2设备2 |, ENABLE);//启动ABP2设备* N" n7 O. d' J- d; ^9 z //RCC_APB1PeriphClockCmd(ABP2设备1 | ABP2设备2 |, ENABLE); //启动ABP1设备 } 6、阅读exti:外部设备中断函数 我的理解——外部设备通过引脚给出的硬件中断,也可以产生软件中断,19个上升、下降或都触发。EXTI0~EXTI15连接到管脚,EXTI线16连接到PVD(VDD监视),EXTI线17连接到RTC(闹钟),EXTI线18连接到USB(唤醒)。* Z/ e, W$ J* Z0 j 基础应用1,设定外部中断初始化函数。按需求,不是必须代码。 用法: void EXTI_Configuration(void)- ^% \- B# g" ?# ~1 e+ l0 E6 W { EXTI_InitTypeDef EXTI_InitStructure; //外部设备中断恢复默认参数 EXTI_InitStructure.EXTI_Line = 通道1|通道2; //设定所需产生外部中断的通道,一共19个。" {7 B* A6 p7 L5 g& |1 g9 |# s EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //设置中断模式 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发 4 X) z3 ^ i d% n6 e+ f- EEXTI_InitStructure.EXTI_LineCmd = ENABLE; //启动中断的接收 EXTI_Init(&EXTI_InitStructure); //外部设备中断启动 } ; w, }6 i- A: d7、阅读dma:通过总线而越过CPU读取外设数据 我的理解——通过DMA应用可以加速单片机外设、存储器之间的数据传输,并在传输期间不影响CPU进行其他事情。这对于入门开发基本功能来说没有太大必要,这个内容先行跳过。& H3 V# l5 h/ ]5 d" A; M- v 8、阅读systic:系统定时器 我的理解——可以输出和利用系统时钟的计数、状态。- r \; ]6 B7 N) l 基础应用1,精确计时的延时子函数。推荐使用的代码。 用法: 6 \4 J; b: M( ^1 n- l& \( y7 t. X( ustatic vu32 TimingDelay; //全局变量声明: ^& h$ Y2 R+ @0 A void SysTick_ Configuration (void) //systick初始化函数 { SysTick_CounterCmd(SysTick_Counter_Disable); //停止系统定时器- |9 X- w0 e5 g2 b5 O3 K2 @ - W- S9 W4 S3 C; Q- X5 k, kSysTick_ITConfig(Disable); //停止systick中断7 d% B1 i/ C! W5 J* F SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //systick使用HCLK作为时钟源,频率值除以8。 SysTick_SetReload(9000); //重置时间1毫秒(以72MHz为基础计算) SysTick_ITConfig(Enable); //开启systic中断1 G u! ~: P; X2 L }7 m( q0 {' H% h: b/ r# k& ? void Delay (u32 nTime) //延迟一毫秒的函数 {* D4 u2 o2 s- m SysTick_CounterCmd(SysTick_Counter_Enable); //systic开始计时 TimingDelay = nTime; //计时长度赋值给递减变量 6 T/ m* o$ o- Ywhile(TimingDelay != 0); //检测是否计时完成 SysTick_CounterCmd(SysTick_Counter_Disable); //关闭计数器 SysTick_CounterCmd(SysTick_Counter_Clear); //清除计数值3 w% d$ N5 {+ S. `' K0 f! r } void TimingDelay_Decrement(void) //递减变量函数,函数名由“stm32f10x_it.c”中的中断响应函数定义好了。+ d a" M9 A/ L9 F* Y% r# x { if (TimingDelay != 0x00) //检测计数变量是否达到0 { TimingDelay--; //计数变量递减0 R7 C% S4 |' d) d D+ v }" p% Z+ B8 Q0 z8 C$ ? }5 ?$ j! c# W+ h5 H 注:建议熟练后使用,所涉及知识和设备太多,新手出错的可能性比较大。新手可用简化的延时函数代替:* y3 n: t& e, G2 ~ void Delay(vu32 nCount) //简单延时函数 {8 y* u4 |+ R! m z for(; nCount != 0; nCount--); //循环变量递减计数 }0 d" Z0 y8 u# S5 e4 E 当延时较长,又不需要精确计时的时候可以使用嵌套循环: void Delay(vu32 nCount) //简单的长时间延时函数$ t$ K. c; U- A7 R1 t, e {int i; //声明内部递减变量 : q5 h) m; |( ` for(; nCount != 0; nCount--) //递减变量计数<span lang="EN-US" style="font-size:12.0pt;mso-bidi-font-size:10.5pt;line-height:150%;font-family:宋体;mso-bidi-font-family:宋体;mso-font-kerning:0pt"> {for (i=0; i |
微信公众号
手机版