stm32初学例程.docx
《stm32初学例程.docx》由会员分享,可在线阅读,更多相关《stm32初学例程.docx(16页珍藏版)》请在冰豆网上搜索。
stm32初学例程
<2011-1-6>
Ifanerror,pleasecontactauthor,tobecorrected.
Forotheruses,indicatethesource,toexpressmyrecognitionoftheresults.
Thankyou.
Introduction
由于公司需要,以及充满对arm的向往,开始学习STM32.。
与8位单片机不同,32位处理器的开发变得更加复杂,同时也伴随着性能和功能的显著提高。
由于初学STM32,遇到了很多莫名其妙的问题,但是总归是在自己的摸索中一个个的解决了。
说来惭愧,三个星期天天忙STM32,总算实现了几个常用的功能,心中窃喜——arm也不过如此嘛!
当然,STM32许多过人之处还没有细细研究,巧妙设计之处还没有完全的感受到,暂且就当是小小的步入STM32开发初期阶段吧。
为了纪念STM32学习过程的辛劳和无助,记下我的学习过程,与大家共勉。
也希望能为广大的初学者提供小小的帮助。
如有任何问题和建议,您可以联系。
此文章所采用的开发环境如下
A、开发板、仿真器:
使用的是STM32F103C8-PKT+ST-LINK;
B、开发环境:
IAREmbeddedWorkbenchforARM6.10Kickstart;
C、Firmware:
STM32F10x_StdPeriph_Lib_V
首先安装IAREmbeddedWorkbenchforARM,32KKickstartEdition;
下载STM32F10x_StdPeriph_Lib_V;
购买一块开发板,通过ST-Link进行仿真和调试;
(所有的资源都可以到IAR和ST官网上下载,资源的获取也是很重要的,要是自己不培养找资源的功夫,就不是一个好的开发人员,这里就不留网址了)
关于编译环境和仿真方法可以参考我的另一篇记录环境搭建的文章——《EWARM_STM32_Use_Instructions》。
在成功搭建开发环境之后,我们就可以对STM32进行深入的学习了,STM32功能繁多,不可以一下子学习所有的知识,因此采用各个击破,由简转难的学习方法,一步步的学会STM32的功能。
总之,我们需要调通每一个经常使用到的功能。
而本篇文章就是记录了调通某些功能的历程,以及在调试过程中可能会出现的问题。
由于自身能力的限制,对有些知识点可能理解的不是很透彻,因此错误难免,希望谅解并给出指导建议。
您可以通过联系我,谢谢。
在使用固件库时,需要自己有点C语言的相关基础,如结构体、枚举、指针等;
1GPIOTest(端口操作实验)
GPIO实验是最简单,也是一般最先开始的一个实验,他可以搭建一个最小的工程项目,之后,所有的实验都可以建立在该项目之上,从而节省了在搭建过程中所消耗的时间和精力。
建议,当该实验顺利完成后,作为一个模板,供以后实验使用,确保您可以将精力花费在需要实现的功能上。
关于环境的搭建,您可以参考《EWARM_STM32_Use_Instructions》;
本实验需要实现:
四个LED的简单控制。
1.1硬件设计:
1.确认硬件连接:
根据开发板原理图,如图,得知:
与LED相连的有PB12、PB13、PB14、PB15;
以下就是对这四个引脚的配置,及相关操作;
1.2软件设计:
//main()程序开始……
1.2.1头文件:
#include"stm32f10x.h"
#include"main.h"
//#include"k_gpio.h"//已经转移到main函数中;
#defineVECT_TAB_RAM//选择在RAM中调试;
//main()函数:
1.2.2系统初始化
SystemInit();//选择系统运行时钟,默认是72MHz,可以调试跟踪进行修改;
#ifdefVECT_TAB_RAM//设置仿真调试区域,这里设置成在RAM中;
//SettheVectorTablebaselocationat0x20000000
NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);
#else/*VECT_TAB_FLASH*/
//SettheVectorTablebaselocationat0x08000000
NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);
#endif
1.2.3GPIO配置
//首先,选择GPIOB外设时钟;只有选择好时钟后,才可以进行下面的配置;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//配置端口,开始时,不需要知道所有的细节,从字面上理解就ok;
gpio.GPIO_Pin=GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
gpio.GPIO_Speed=GPIO_Speed_50MHz;
gpio.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(GPIOB,&gpio);
GPIO_SetBits(GPIOB,GPIO_Pin_12);//将端口拉高,灭LED灯;
GPIO_SetBits(GPIOB,GPIO_Pin_13);
GPIO_SetBits(GPIOB,GPIO_Pin_14);
GPIO_SetBits(GPIOB,GPIO_Pin_15);
如此,GPIOB连接LED的四个端口都配置好了;
1.2.4GPIO操作
While
(1)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_12);
Delay(0xffffff);
GPIO_ResetBits(GPIOB,GPIO_Pin_13);
Delay(0xffffff);
GPIO_ResetBits(GPIOB,GPIO_Pin_14);
Delay(0xffffff);
GPIO_ResetBits(GPIOB,GPIO_Pin_15);
Delay(0xffffff);
Delay(0xffffff);
Delay(0xffffff);
GPIO_SetBits(GPIOB,GPIO_Pin_12);
Delay(0xffffff);
GPIO_SetBits(GPIOB,GPIO_Pin_13);
Delay(0xffffff);
GPIO_SetBits(GPIOB,GPIO_Pin_14);
Delay(0xffffff);
GPIO_SetBits(GPIOB,GPIO_Pin_15);
Delay(0xffffff);
GPIO_ResetBits(GPIOB,GPIO_Pin_12);
GPIO_ResetBits(GPIOB,GPIO_Pin_13);
GPIO_ResetBits(GPIOB,GPIO_Pin_14);
GPIO_ResetBits(GPIOB,GPIO_Pin_15);
}
如此而已;这是最简单的实验,可以为此建立一个拥有自己特色的工程模板;
1.3Test注意
A、硬件必须首先确保正确;
B、开发环境搭建确保正确;
C、系统时钟的选择要清楚;仿真所处的区域要清楚;
D、外设时钟的配置是第一位的,其他配置都在其后;
2Time2Test(Time2定时实验)
Timer作为控制器和处理器的一个重要的组成部分,是几乎所有系统都需要的一个模块,可以提高程序的实时性、精确性,以及安全性,是最为重要的一个学习方面;
STM32有着丰富的Time系统,很容易使初次接触的人产生恐惧,不过,归咎起来,他的作用也只是定时和计数,只不过衍生的功能比较强大,有PWM,比较捕获,强制输出等,其实不需要所有的功能都掌握,您只需要用到什么功能再去学习某个功能即可;
本实验需要实现:
使用Time2进行定时的功能,使得LED灯进行相应时间的闪烁。
2.1硬件设计
在Time2上,主要是芯片内部实现,所以Time2无需关注硬件;
操作的LED,我们需要实现与PB12引脚相连的LED的亮灭;
2.2软件设计
#include"stm32f10x.h"
#include"main.h"
//#include"k_gpio.h"//已经转移到main函数中;
//#include"k_time2.h"//本实验增加部分,但已经转移到main函数中;
#defineVECT_TAB_RAM
voidmain()
{
GPIO_InitTypeDefgpio;
TIM_TimeBaseInitTypeDeftime2;//本实验增加部分
NVIC_InitTypeDefnvic;//本实验增加部分
SystemInit();
#ifdefVECT_TAB_RAM
//SettheVectorTablebaselocationat0x20000000
NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);
#else/*VECT_TAB_FLASH*/
//SettheVectorTablebaselocationat0x08000000
NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);
#endif
//GPIOB端口配置
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
gpio.GPIO_Pin=GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
gpio.GPIO_Speed=GPIO_Speed_50MHz;
gpio.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(GPIOB,&gpio);
GPIO_SetBits(GPIOB,GPIO_Pin_12);
GPIO_SetBits(GPIOB,GPIO_Pin_13);
GPIO_SetBits(GPIOB,GPIO_Pin_14);
GPIO_SetBits(GPIOB,GPIO_Pin_15);
//以上已经有过详细的论述,可以参考先前的Test;
//以下是本实验增加的部分;
//Time2配置
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB2Periph_AFIO,ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);//设置Time2中断向量相关;
nvic.NVIC_IRQChannel=TIM2_IRQn;
//nvic.NVIC_IRQChannelPreemptionPriority=0;
nvic.NVIC_IRQChannelSubPriority=1;
nvic.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&nvic);
TIM_DeInit(TIM2);//设置Time2相关;
time2.TIM_Prescaler=0;
time2.TIM_CounterMode=TIM_CounterMode_Up;
time2.TIM_Period=1000;
time2.TIM_ClockDivision=TIM_CKD_DIV1;
//TIM_TimeBaseStructure.TIM_RepetitionCounter
TIM_TimeBaseInit(TIM2,&time2);
TIM_PrescalerConfig(TIM2,0x8c9F,TIM_PSCReloadMode_Immediate);
TIM_ARRPreloadConfig(TIM2,DISABLE);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
TIM_Cmd(TIM2,ENABLE);//启动Time2;
while
(1)
{
}
}
关于系统外设时钟的选择,可以参见相关手册,这是一个比较复杂的关系,这里给个简单的图:
(由红色框图中得知,Time2采用的是APB1之后的时钟系统)
由于本实验,涉及到中断,而且对于端口的操作,是在中断中进行的;
其中中断函数名称的由来,在startup_stm32f10x_hd.s(或其它)文件中,如图:
中断程序如下:
//-----------------------------------------
u8ledflag=0;
voidTIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_FLAG_Update)!
=RESET)
{
TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);
if(ledflag++%2)
{
GPIO_SetBits(GPIOB,GPIO_Pin_12);
}
else
{
GPIO_ResetBits(GPIOB,GPIO_Pin_12);
}
}
}
我想这么简单的中断程序应该没问题吧。
2.3Test注意
A、学会使用以前用过的模板,节省环境搭建时间;
B、学会查看数据手册,理解外设系统时钟的选择原因;
C、学会中断程序的编写,中断向量、函数的获取;
3USARTTest(串口收发实验)
只要是Project,只要是嵌入式开发,我想都免不了使用通讯,来和外界联系;只要使用通讯,最先想到的就是USART。
这是一个很是常用的和非常好用的通讯方式。
所有的处理器、控制器上,基本上都无一例外的增加USART功能。
初学者在经历了环境搭建、GPIO、Time定时之后,就需要接触USART相关了。
本实验需要实现:
USART的中断接收和发送,实现将收到的数据回发出去。
3.1硬件设计
查看开发板原理图,确定好通道连接情况:
引脚是否对,跳线是否短接。
图中显示:
使用PA9(TX)和PA10(RX)和STM32连接。
3.2软件设计
由上述两个实验,我们可以总结出:
1、外设时钟选择时钟是第一位的;
2、只要使用到端口,就需要初始化端口;
3、使用到其他外设,需要一一配置外设时钟;
4、使用中断的,需要配置好中断向量,以及编写中断函数;
本实验开始:
#include"stm32f10x.h"
#include"main.h"
//#incude"k_usart.h"//已经转移到main函数中;
#defineVECT_TAB_RAM
voidmain(void)
{
GPIO_InitTypeDefGPIO_InitStructure;
USART_InitTypeDefUSART_InitStructure;
NVIC_InitTypeDefnvic;
//USART_ClockInitTypeDefUSART_InitClockStructure;
SystemInit();
#ifdefVECT_TAB_RAM
//SettheVectorTablebaselocationat0x20000000
NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);
#else/*VECT_TAB_FLASH*/
//SettheVectorTablebaselocationat0x08000000
NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);
#endif
//以下是USART的配置部分
//-------------------------------------------------------
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);
//-----------------------------------------------
//GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
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_10;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//-----------------------------------------------------------
nvic.NVIC_IRQChannel=USART1_IRQn;
nvic.NVIC_IRQChannelPreemptionPriority=3;
nvic.NVIC_IRQChannelSubPriority=2;
nvic.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&nvic);
//------------------------------------------------------------
//USART_StructInit(&USART_InitStructure);
USART_InitStructure.USART_BaudRate=115200;
USART_InitStructure.USART_WordLength=USART_WordLength_8b;
USART_InitStructure.USART_StopBits=USART_StopBits_1;
USART_InitStructure.USART_Parity=USART_Parity_No;
USART_InitStructure.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_Init(USART1,&USART_InitStructure);
/*
USART_InitClockStructure.USART_CPOL=USART_CPOL_Low;
USART_InitClockStructure.USART_CPHA=USART_CPHA_2Edge;
USART_InitClockStructure.USART_LastBit=USART_LastBit_Disable;
USART_InitClockStructure.USART_Clock=USART_Clock_Disable;
USART_ClockInit(USART1,&USART_InitClockStructure);
*/
USART_Cmd(USART1,ENABLE);
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//先使能接收中断;
USART_ITConfig(USART1,USART_IT_TXE,DISABLE);//先禁止发送中断;
while
(1)
{
//接下来就交给中断处理;
}
}
USART1_IRQn中断函数在stm32f10x_it.c中:
//include"stdio.h"
uint32_tRxBuffer;
voidUSART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1,USART_IT_RXNE)!
=RESET)
{
RxBuffer=USART_ReceiveData(USART1);
USART_ITConfig(USART1,USART_IT_TXE,ENABLE);
USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);
//printf("R");
}
if(USART_GetITStatus(USART1,USART_IT_TXE)!
=RESET)
{
USART_SendData(USART1,RxBuffer);
USART_ITConfig(USART1,USART_IT_TXE,DISABLE);
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
//printf("S");
}
}
详细细节在这里不做论述,可以从命名中得知一般配置usart的步骤;可以F12去探究其缘由,以及涉及的相关寄存器;
3.3Test注意
1、在中断中,需要注意USART的中断条件,当发送中断ENABLE时,只要没有数据处理,就会进入中断,因此需要发送时才打开,不需要时,一定要关闭;
2、还是那句话,先配置外设时钟;
3、关于STM32中断相关配置,可以参考数据手册理解NVIC;
4USARTDMATest(串口DMA收发实验)
5Time3PWMTest(Time3PWM输出实验)
6I2CTest(I2C读写实验)
7ADCText(AD转换实验)