——从0建立第一个STM32工程,点亮LED。
硬件方面:在万利的EK-STM32F开发板上,与LED相连的是GPIO的PC4~PC7,高电平点亮。对于单片机很熟的朋友很容易就知道点亮LED的方法就是通过PC4~PC7输出高电平。关于这一点没什么好说的。
软件方面:
开发的模式仍然是,编写代码,编译,链接,通过开发工具烧写到Flash这样一个步骤。但是如果一上来就使用ST提供的库文件,就会把自己搞得头大,看不到本质。
1、 STM32的存储器组织
STM32的程序存储器、数据存储器、寄存器和输入输出端口被组织在同一个 4GB的线性地址空间内。 可访问的存储器被分为8个512MB的块。数据字节以小端格式存放在存储器中,也即一个字的最低有效字节被存放在该字的最低地址字节中。
片内集成的Flash、SRAM被映射到如下图所示的地址空间中。
SRAM:最高达64KB,地址范围0x2000 0000 ~ 0x2000 FFFF
FLASH:由3个部分组成,Main Block, Information Block。
其中,Main Block用于存放用户程序,最高达512KB,地址范围0x0800 0000 ~ 0x807F FFFF
Information Block又包括System Memory和Option Bytes两个部分。System Memory地址范围0x1FFFF F000 ~ 0X1FFFF F7FF共计2KB,用于存放通过UART1进行ICP编程的BOOTLOADER;Option Bytes包含16个字节,用于(还不知道)
2、 启动(BOOT)配置
细心的朋友一定注意到了上图中的0X0000 0000 --- 0X0007 FFFF这个512KB的地址范围了。它用于什么目的呢?它是STM32上电后,开始执行代码的地址区域。也就是说,STM32上电后,是从0X0000 0000这个地址开始执行代码的。但是,问题在于,这个地址范围既没有FLASH也没有SRAM呀,怎么回事呢?
原来,STM32可以通过BOOT0,BOOT1两个管脚来动态的把上面提到的存储区域映射到0x0000 0000 --- 0X0007 FFFF这个区域中。
这就是说,可以选择从内嵌FLASH、SRAM、内嵌bootloader中启动。
3、 新建IAR工程
有了上面这些基础知识后,可以开始我们的第一次尝试了。
第一步,新建IAR工程,(略,我想大家自己摸索一下应该没有什么问题)
第二步,设置选项,这一步的目的是告诉IAR如何编译我们的工程。有以下几个关键点要注意:
1) 设置Target,选择core为coretex-m3,小端模式,堆栈4字节对齐
2) 设置Linker,在Output选项卡下选中C-SPY
Extra Output中,选中Generate extra output file
3) 链接脚本,在Linker的Config选项卡下设置使用自己的链接脚本。该文件控制了如何为目标生成符合要求的可执行代码。
修改IAR的安装目录\IAR Systems\Embedded Workbench 4.0Kickstart\arm\config下的默认lnkarm.xcl文件如下几个部分:
代码段,位于Flash区,STM32F103VBT6有128K,所以改成如下
//******************************************************************
// Read-only segments mapped to ROM.
//******************************************************************
//-DROMSTART=08000
//-DROMEND=FFFFF
-DROMSTART=0x8000000
-DROMEND=0x801FFF
中断向量表范围
//************************************************
// Address range for reset and exception
// vectors (INTVEC).
// The vector area is 32 bytes,
// an additional 32 bytes is allocated for the
// constant table used by ldr PC in cstartup.s79.
//************************************************
//-Z(CODE)INTVEC=00-3F
-Z(CODE)INTVEC=ROMSTART-ROMEND
数据段,位于SRAM,STM32F103VBT6有20KB
//*********************************************************************
// Read/write segments mapped to RAM.
//*********************************************************************
//-DRAMSTART=100000
//-DRAMEND=7FFFFF
-DRAMSTART=0x20000000
-DRAMEND=0x20004FFF
堆栈和堆设置
//*********************************************************************
// Stack and heap segments.
//*********************************************************************
//-D_CSTACK_SIZE=2000
-D_CSTACK_SIZE=800
// -D_SVC_STACK_SIZE=10
-D_IRQ_STACK_SIZE=100
//-D_HEAP_SIZE=8000
-D_HEAP_SIZE=40
4、 编写代码
代码的任务是点亮LED,其方法和单片机类似,方位GPIO等外设对应的IO端口,它们位于0x4000 0000 --- 0X5FFF FFFF这个块里,用指向这个地址范围的指针来访问它们。
代码如下:
#define GPIOC_CRL (*((unsigned int *)(0x40011000)))
#define GPIOC_BSRR (*((unsigned int *)(0x40011010)))
#define GPIOC_BRR (*((unsigned int *)(0x40011014)))
#define RCC_APB2ENR (*((unsigned int *)(0x40021018)))
void delay(void)
{
unsigned int i;
for(i = 0; i < 0xffff; ++i)
;
}
int main(void)
{
//使能PORTC时钟
RCC_APB2ENR |=(1<<4);
//将GPIOC_CRL高16位都清0
//这样CNF为00,即选择为推挽输出模式
GPIOC_CRL &= 0x0000FFFF;
//MODE选择为11,即50MHz输出模式
GPIOC_CRL |= 0x33330000;
while(1)
{
GPIOC_BRR=(1<<4); //灭 LED5
GPIOC_BSRR=(1<<7);//亮 LED2
delay();
GPIOC_BRR=(1<<7); //灭 LED2
GPIOC_BSRR=(1<<6);//亮 LED3
delay();
GPIOC_BRR=(1<<6); //灭 LED3
GPIOC_BSRR=(1<<5);//亮 LED4
delay();
GPIOC_BRR=(1<<5); //灭 LED4
GPIOC_BSRR=(1<<4);//亮 LED5
delay();
}
}
5、 编译下载
为了下载到开发板,可以使用开发板自带的ST-LINK工具。工程里也需要相应的设置;
Debugger中,选择第三方驱动
第三方驱动中设置安装好的ST-LINK驱动。
设置好后,Make,Debug,GO就OK了。