写在前面的话
自从去年接触STM32以来,已经有一年多了,看上STM32,当时确实是看上他的性价比,可以用串口下载,编译器也有KEIL支持,以前用过51,后面转学AVR,把KEIL放到一边了,大概两三年没动KEIL了,但是当时我认为,自己也快毕业了,大学里面就学了51和AVR,MSP430做过板子,但是不能编程,可能我的设计有问题,于是就没去弄它了,也接触过凌阳的61板子,玩了玩语音识别,到后大三的时候就想学ARM了,因为很多时候AVR资源确实是不够的,我做HIFI耳放就体会到了这一点.后面左看右看看上了LPC的2148,于是网购了一片,专门为她设计了一款板子,结果还是不能下载,良久,无果,弃之.
某日,得TFTLCD一片,喜之,用AVR驱动,终成功! 结果发现MEGA32,存储的BMP图片才一点点大,我想这样是不行了,得升级,至少也要搞个全屏的图片出来.于是又开始瞄上了ARM,加上之前失败的教训和AVR资源不足的缺点,仔细选型,最终看上了STM32.价格低,编程方便,资源多. 于是下狠心,买了两片回来,并为其设计了一个开发板.于是开始了我的STM32之旅...
转眼一年过去了,STM32上的资源也大部分过了一遍,从最基本的IO操作,到DMA,现在还剩下USB,CAN等没整,等以后整了之后再和大家分享.
现在STM32在网友间用的已经很普遍了,这里我只是把我当时学习的一些代码整理一下发上来,给需要的网友参考借鉴.也欢迎各位指出我代码里面的错误,感激不尽!
本人有强烈的控制欲,所以不屑用库,所有代码都是对寄存器操作,任何问题都可以很快找到答案,对库有癖好的就可以不用看了.灯论坛的板子好了,我会移植到论坛的板子上验证一下.本人文采不好,就不再废话了,希望我的代码能帮到各位,如果对我的代码有任何疑问,欢迎提问.共勉!
正点原子@深圳南山一农民房
2009/12/22
跑马灯
刚开始学STM32,最烦的莫过于繁多的寄存器了,如果你想找STM32的书,我劝你还是免了,能写STM32的书还没问世,至少我没见到像样的.无非是抄数据手册的.所以,要求不高的话,建议拿一本<<CM权威指南>>+<<STM32用户手册>>+KEIL自带的例程边看边学,这样很容易上手.因为KEIL可以电脑仿真,还提供一些寄存器才查看,这样就会比较明白.
对于时钟的操作,我有了一些比较好的设置函数,放在sys.c里面,具体的如下:
#include <stm32f10x_lib.h>
#include "sys.h"
//系统时钟初始化
//使用外部8M晶振,PLL到72M频率
//正点原子@SCUT
//2009/12/09
//V1.3
//把NVIC KO了,没有使用任何库文件!
//中断初始化 RTC,USART已经测试,其他待测试!
//设置向量表偏移地址
//NVIC_VectTab:基址
//Offset:偏移量
//CHECK OK
//091207
void 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的向量表偏移寄存器
//用于标识向量表是在CODE区还是在RAM区
}
//设置NVIC分组
//NVIC_Group:NVIC分组 0~4 总共5组
//CHECK OK
//091209
void MY_NVIC_PriorityGroupConfig(u8 NVIC_Group)
{
u32 temp,temp1;
temp1=(~NVIC_Group)&0x07;//取后三位
temp1<<=8;
temp=SCB->AIRCR; //读取先前的设置
temp&=0X0000F8FF; //清空先前分组
temp|=0X05FA0000; //写入钥匙
temp|=temp1;
SCB->AIRCR=temp; //设置分组
}
//设置NVIC
//NVIC_PreemptionPriority:抢占优先级
//NVIC_SubPriority :响应优先级
//NVIC_Channel :中断编号
//NVIC_Group :中断分组
//注意优先级不能超过设定的组的范围!否则会有意想不到的错误
//CHECK OK
//091209
void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group)
{
u32 temp;
u8 IPRADDR="NVIC"_Channel/4; //每组只能存4个,得到组地址
u8 IPROFFSET="NVIC"_Channel%4;//在组内的偏移
IPROFFSET=IPROFFSET*8+4; //得到偏移的确切位置
//MY_NVIC_PriorityGroupConfig(NVIC_Group);//设置分组
temp=NVIC_PreemptionPriority<<(4-NVIC_Group);
temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);
temp&=0xf;//取低四位
if(NVIC_Channel<32)NVIC->ISER[0]|=1<<NVIC_Channel;//使能中断位(要清除的话,相反操作就OK)
else NVIC->ISER[1]|=1<<(NVIC_Channel-32);
NVIC->IPR[IPRADDR]|=temp<<IPROFFSET;//设置响应优先级和抢断优先级
}
//不能在这里执行所有外设复位!否则至少引起串口不工作.
//把所有时钟寄存器复位
//CHECK OK
//091209
void MYRCC_DeInit(void)
{
RCC->APB1RSTR = 0x00000000;//复位结束
RCC->APB2RSTR = 0x00000000;
RCC->AHBENR = 0x00000014; //flash时钟,闪存时钟使能.DMA时钟关闭
RCC->APB2ENR = 0x00000000; //外设时钟关闭.
RCC->APB1ENR = 0x00000000;
RCC->CR |= 0x00000001; //使能内部高速时钟HSION
RCC->CFGR &= 0xF8FF0000; //复位SW[1:0],HPRE[3:0],PPRE1[2:0],PPRE2[2:0],ADCPRE[1:0],MCO[2:0]
RCC->CR &= 0xFEF6FFFF; //复位HSEON,CSSON,PLLON
RCC->CR &= 0xFFFBFFFF; //复位HSEBYP
RCC->CFGR &= 0xFF80FFFF; //复位PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE
RCC->CIR = 0x00000000; //关闭所有中断
//配置向量表
#ifdef VECT_TAB_RAM
MY_NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else
MY_NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
}
//THUMB指令不支持汇编内联
//采用如下方法实现执行汇编指令WFI
//CHECK OK
//091209
__asm void WFI_SET(void)
{
WFI;
}
//进入待机模式
//check ok
//091202
void Sys_Standby(void)
{
SCB->SCR|=1<<2;//使能SLEEPDEEP位 (SYS->CTRL)
RCC->APB1ENR|=1<<28; //使能电源时钟
RCC->APB1ENR|=1<<27; //使能备份时钟
PWR->CSR|=1<<8; //设置WKUP用于唤醒
PWR->CR|=1<<2; //清除Wake-up 标志
PWR->CR|=1<<1; //PDDS置位
WFI_SET(); //执行WFI指令
//__WFI();
}
//后备寄存器写入操作
//reg:寄存器编号
//reg:要写入的数值
////check ok
////091202
//void BKP_Write(u8 reg,u16 dat)
//{
// RCC->APB1ENR|=1<<28; //使能电源时钟
// RCC->APB1ENR|=1<<27; //使能备份时钟
// PWR->CR|=1<<8; //取消备份区写保护
// switch(reg)
// {
// case 1:
// BKP->DR1=dat;
// break;
// case 2:
// BKP->DR2=dat;
// break;
// case 3:
// BKP->DR3=dat;
// break;
// case 4:
// BKP->DR4=dat;
// break;
// case 5:
// BKP->DR5=dat;
// break;
// case 6:
// BKP->DR6=dat;
// break;
// case 7:
// BKP->DR7=dat;
// break;
// case 8:
// BKP->DR8=dat;
// break;
// case 9:
// BKP->DR9=dat;
// break;
// case 10:
// BKP->DR10=dat;
// break;
// }
//}
//系统软复位
//CHECK OK
//091209
void Sys_Soft_Reset(void)
{
SCB->AIRCR =0X05FA0000|(u32)0x04;
}
//外部8M,则得到72M的系统时钟
//pll:选择的倍频数,从2开始,最大值为16
//CHECK OK
//091209
void Stm32_Clock_Init(u8 PLL)
{
unsigned char temp="0";
MYRCC_DeInit(); //复位并配置向量表
RCC->CR|=0x00010000; //外部高速时钟使能HSEON
while(!(RCC->CR>>17));//等待外部时钟就绪
RCC->CFGR=0X00000400; //APB1/2=DIV2;AHB=DIV1;
PLL-=2;//抵消2个单位
RCC->CFGR|=PLL<<18; //设置PLL值 2~16
RCC->CFGR|=1<<16; //PLLSRC ON
FLASH->ACR|=0x32; //FLASH 2个延时周期
RCC->CR|=0x01000000; //PLLON
while(!(RCC->CR>>25));//等待PLL锁定
RCC->CFGR|=0x00000002;//PLL作为系统时钟
while(temp!=0x02) //等待PLL作为系统时钟设置成功
{
temp=RCC->CFGR>>2;
temp&=0x03;
}
}
设置好时钟之后,其他的就好办了,和AVR的操作差不多了(记得IO操作的时候先开启时钟!!!),看如下的主函数代码:
//LED端口定义
#define LED0 (1<<10)// PC10
#define LED1 (1<<11)// PC11
#define LED2 (1<<12)// PC12
#define LED3 (1<<2) // PD2
//LEDIO 操作函数
#define LED0_SET(x) GPIOC->ODR=(GPIOC->ODR&~LED0)|(x ? LED0:0)
#define LED1_SET(x) GPIOC->ODR=(GPIOC->ODR&~LED1)|(x ? LED1:0)
#define LED2_SET(x) GPIOC->ODR=(GPIOC->ODR&~LED2)|(x ? LED2:0)
#define LED3_SET(x) GPIOD->ODR=(GPIOD->ODR&~LED3)|(x ? LED3:0)
//LED IO初始化
void led_init(void)
{
RCC->APB2ENR|=1<<4; //使能PORTC时钟
GPIOC->CRH&=0XFFF000FF;
GPIOC->CRH|=0X00033300;//PC.10/11/12推挽输出
GPIOC->ODR|=0X1C00; //PC.10/11/12 输出高
RCC->APB2ENR|=1<<5; //使能PORTD时钟
GPIOD->CRL&=0XFFFFF0FF;
GPIOD->CRL|=0X300; //PD.2推挽输出
GPIOD->ODR|=1<<2; //PD.2输出高
}
int main(void)
{
Stm32_Clock_Init(9);//72M
delay_init(72); //延时初始化
//uart_init(72,9600); //设置波特率
led_init();
while (1)
{
LED0_SET(0);
delay_ms(500);
LED0_SET(1);
LED1_SET(0);
delay_ms(500);
LED1_SET(1);
LED2_SET(0);
delay_ms(500);
LED2_SET(1);
LED3_SET(0);
delay_ms(500);
LED3_SET(1);
}
}
至此,一个跑马灯程序就完成了.
源码:https://static.assets-stash.eet-china.com/album/old-resources/2009/12/22/5bbbfc5d-2aec-4794-aec3-7110ffecc983.rar
这两天把STMSKY的板子焊接好了,以后代码就基于这个平台了
新代码:https://static.assets-stash.eet-china.com/album/old-resources/2009/12/31/bcceda0a-b9ea-4668-896b-a2f0ee475589.rar
这里代码做了点修改,下面是运行结果:
可以看到红绿蓝三个灯以此点亮.
用户584305 2013-5-9 13:09
用户607352 2011-3-31 16:06
用户306328 2011-3-9 12:32
liujun6037_345432000 2010-12-5 21:52
用户1540889 2010-12-3 22:42