EDN首页   博客首页 用户登陆  |  注册
aaa
发表于 2010/2/28 2:41:34

0

关于投票

给我一个不选STM32的理由?

最近,看到论坛上很多朋友讨论,1,AVR涨价.2,AVR/STM32缺货.3,STM8和AVR性能对比.
其实,识别下来,就是STM和AVR的对抗.
低端: AVR  PK STM8.
高端:STM32 PK AVR32
低端市场,我用过AVR,没用过STM8.AVR是很成功的一款芯片,功耗低,性能强.较之前的51,性能提升了好几个档次.如果一个初学者,学完了51,在学AVR,肯定就会对AVR爱不释手.我也是这么过来的,AVR对当时的我来说可谓是要啥有啥.所以从大二开始,一直用到毕业.PIC据说也不错,但是很遗憾,我们学校,没看到几个搞PIC的,因为这个东西价格太高了,对我们学生来说,基本上不考虑.当然,有钱人例外.其次,AVR的下载也是很方便的.和51的可以通用.这其中双龙电子对avr的支持,至少在国内来说,爱特梅尔是要感谢他们的.至于STM8,我没有详细了解,我估计他存在的目的,就是要把8位市场给占领了.他最大的对手,估计就是AVR和51了.目前AVR的局势,岌岌可危,如果真要涨价,很可能就快要退出历史舞台了.STM8目前最低端的是STM8S103F2 最少引脚数是20脚的,淘宝最低售价是3.5元,AVR同样配置(仅仅指SRAM和FLASH)的芯片,价格在3块左右.基本不分上下.其他功能方面也很相似.STM8最高端的,STM8S208MB,淘宝价格在15元左右,而同样配置的avr芯片只有MEGA128了,还少了2k的ram和CAN控制器,不过多了总线控制器.但是MEGA128的价格,在30块钱左右,毫无竞争力了,这就.这样的价格,STM32F103都能买到很好的芯片了.15块钱左右,基本只够买个MEGE32,而mega32和STM8S208MB相比,显然差距很明显.所以果真AVR要涨价,我建议,没学AVR的就可以跳过avr了,学过的,就赶紧选择新的MCU.不过STM8的下载,好像不如AVR那么方便,这方面,我没有了解过,STM8,打造最便宜的下载器,不知道要多少钱?还请用过的朋友回答一下.

高端市场,ST最近几年,对STM32的推广,可谓是不遗余力.效果也是很显著的.我是阴错阳差,在08年开始学STM32,而且STM32的价格,现在也很便宜,当时,STM32F103RBT6也就30块钱,外设功能是很强悍了,128Kfalsh,20K sram,USB,12位ADC,SPI,IIC,TIMER,USART,RTC等,基本上,你能想到的,它都有了.显然,次时的MEGA128已经毫无竞争力了.现在STM32低配置的芯片,STM32F101C4,16K FLASH,4K SRAM,价格在10块钱左右.F103较低配置的STM32F103C8,也卖到了13块钱一个,64K FLASH,20K SRAM,带USB和CAN.单从这2个数据,就能说明很多问题了.LM3S,应该是和STM32一同推上市场的,至少不会比STM32晚,据说当时敢尝CM3螃蟹的就流名和ST.周立功还选择了推流明,后面也不知道什么原因,一直没见流明起来,可能周立功和流明,都有错吧(脑子被驴踢了可能).却见STM32是打得红红火火.如今流明(被TI收购了)已经没办法和STM32竞争了.估计老周也很郁闷吧,当时怎么就没推STM32呢?呵呵. 继续说STM32,STM32现在推出的型号,从最低的10块钱的,到最高端的STM32F103ZET6,价格也不过40元不到.其中包括的型号,有50种之多.用户可以随便选择满足自己需求的产品.高端方面,STM32还推了F105/F107系列.强化了USB和网络的功能.这方面AVR32,从淘宝上看到的最低价格是30元左右,具体配置没去看了.AVR32同STM32最大的缺点就是下载程序不方便,人家得专门为你做个下载器,或者从你那里买,我们论坛上好像也有人搞了下载器出来,还真佩服这些哥们,挺厉害的.不过STM32呢?支持JTAG,支持串口下载. 这就把学习STM32的门槛一下降低了,加上KEIL对STM32的支持,比学习AVR的门槛还低了.这就很快的培养了大批使用者.其次,STM32的中文支持,做的也很到位,中文数据手册,CM3权威指南,也都有中文版本的,给用户提供了很大的便利.反观其他,LPC和爱特梅尔由于之前不敢吃螃蟹,到现在他们的CM3构架芯片,还没见到,LM3S虽然和ST一起吃了螃蟹,不过没搞好,算是玩完了.所以,现在就剩下ST独领风骚了.


总结STM32的成功经验:
1,芯片价格低(最低10块)
2,下载方便(串口下载,无需用户增加任何成本)
4 编译器支持(KEIL和IAR)
5,资源丰富(无论是FLASH,还是SRAM,还是外设,都做的很不错,当然还少了EEPROM,有点遗憾,但无伤大雅)
6,学习方便(有专门的库支持,有很多范例代码,有中文数据手册,有中文的权威指南)
7,后续升级有望(F101->F103->F105->F107->CM4...)

因为有以上7个原因,导致了STM32在最近2年迅速崛起,已近到了可以吃掉AVR 的地步了.AVR依我看来,只在价格低于10块钱的时候,才和STM32有竞争力,低端由于STM8的存在,对AVR也构成了一定威胁,但是由于STM8的支持,不如STM32好,比如下载不方便,编译器不好搞等因素.所以暂时还没能和AVR拼,但是一旦AVR要涨价,就是逼着我们用户去学STM8了,到时候,AVR就在这块市场也要输掉了.

ARM7和STM32我选择了STM32,说不出为什么,也许那一年我的LPC2134能下载成功,我现在用的就是LPC的ARM7.不过幸好那个时候我没有下载成功,才使我认识了STM32.
最后,一个价格低,入门低,功能强的芯片,是没道理不火起来的.


以上纯属个人愚见,欢迎各位网友拍板.

系统分类: ARM  |  用户分类: STM32学习  |  标签: STM32 LPC LM3S AVR AVR32  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(226) | 回复(2)

发表于 2009/12/31 21:52:02

0

关于投票

跟我学STM324 2.8寸LCD显示

    该代码基于STMSKY网络开发板硬件.驱动板载2.8寸LCD,采用FSMC 16位方式驱动.其中最关键的是对FSMC进行初始化,这个搞定了,其他的就比较容易了,这里我全部使用寄存器操作,可读性没库函数好,但是等你熟悉了之后,这个问题就不存在了,而且代码更加简洁.

LCD驱动部分代码如下:

#include "lcd.h"
#include "stdlib.h"
#include "font.h"
u16 POINT_COLOR = 0x0000, BACK_COLOR = 0xFFFF;
//STMSKY开发板2.8寸TFT液晶驱动(9325)
//FSMC驱动
//正点原子@深圳南山
//2009.12.31
//V1.1

//写寄存器
void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue)
{    
 LCD->LCD_REG = LCD_Reg;//写入要写的寄存器序号 
 LCD->LCD_RAM = LCD_RegValue;//写入数据
}   
//读寄存器
u16 LCD_ReadReg(u8 LCD_Reg)
{            
 LCD->LCD_REG = LCD_Reg;//写入要读的寄存器序号   
 return (LCD->LCD_RAM);//返回读到的值
}  
//开始写GRAM
void LCD_WriteRAM_Prepare(void)
{
 LCD->LCD_REG = R34;

//LCD写GRAM
void LCD_WriteRAM(u16 RGB_Code)
{          
 LCD->LCD_RAM = RGB_Code;//写十六位GRAM
}
//LCD读GRAM
u16 LCD_ReadRAM(void)
{  
 u16 ts;
 LCD->LCD_REG = R34; //选择GRAM地址
 ts=LCD->LCD_RAM; //第一个数据放弃
 ts=LCD->LCD_RAM; //得到数据
 return ts;
}
//LCD开启显示
void LCD_DisplayOn(void)
{       
 LCD_WriteReg(R7, 0x0173); //26万色显示开启

//LCD关闭显示
void LCD_DisplayOff(void)
{   
 LCD_WriteReg(R7, 0x0);//关闭显示
}   
//LCD延时函数 10MS
void Delay (u32 nCount)
{
 volatile int i;   
 for (i=0;i<nCount*100;i++);
}
//设置光标位置
//Xpos:横坐标
//Ypos:纵坐标
void LCD_SetCursor(u8 Xpos, u16 Ypos)
{
 LCD_WriteReg(R32, Xpos);
 LCD_WriteReg(R33, Ypos);
}
//画点
//x:0~239
//y:0~319
//POINT_COLOR:此点的颜色
void LCD_DrawPoint(u8 x,u16 y)
{
 LCD_SetCursor(x,y);//设置光标位置
 LCD->LCD_REG=R34;//开始写入GRAM
 LCD->LCD_RAM=POINT_COLOR;
}
 
//初始化lcd
//该初始化函数可以初始化各种ILI93XX液晶,但是其他函数是基于ILI9300的!!!
//在其他型号的驱动芯片上没有测试!
void LCD_Init(void)
{
 u16 DeviceCode; 
 RCC->AHBENR|=1<<8;    //使能FSMC时钟
 RCC->APB2ENR|=0X01E5;    //使能PORTA,D,E,F,G AFIO时钟

 GPIOA->CRH&=0XFFFFFFF0;//GPIOA.8 推挽输出 背光
 GPIOA->CRH|=0XFFFFFFF3;
 //PORTD复用推挽输出  
 GPIOD->CRH&=0X00FFF000;
 GPIOD->CRH|=0XBB000BBB;
 GPIOD->CRL&=0XFF00FF00;
 GPIOD->CRL|=0X00BB00BB;    
 //PORTE复用推挽输出  
 GPIOE->CRH&=0X00000000;
 GPIOE->CRH|=0XBBBBBBBB;
 GPIOE->CRL&=0X0FFFFFFF;
 GPIOE->CRL|=0XB0000000;
 //PORTF复用推挽输出                   
 GPIOF->CRL&=0XFFFFFFF0;
 GPIOF->CRL|=0X0000000B;
 //PORTG12复用推挽输出 A0                  
 GPIOG->CRH&=0XFFF0FFFF;
 GPIOG->CRH|=0X000B0000;
     
 //寄存器清零
 //bank1有NE1~4,每一个有一个BCR+TCR,所以总共八个寄存器。
 //这里我们使用NE4 ,也就对应BTCR[6],[7]。       
 FSMC_Bank1->BTCR[6]=0X00000000;
 FSMC_Bank1->BTCR[7]=0X00000000;
 FSMC_Bank1E->BWTR[6]=0X00000000;
 //操作BCR寄存器 使用异步模式
 FSMC_Bank1->BTCR[6]|=1<<12;//存储器写使能
 FSMC_Bank1->BTCR[6]|=1<<4; //存储器数据宽度为16bit     
 //操作BTR寄存器           
 FSMC_Bank1->BTCR[7]|=1<<9; //数据保存时间为3个HCLK   
 //闪存写时序寄存器 
 FSMC_Bank1E->BWTR[6]=0x0FFFFFFF;//默认值
 //使能BANK4(PC卡设备)
 FSMC_Bank1->BTCR[6]|=1<<0; 
      
 Delay(5); // delay 50 ms
 LCD_WriteReg(0x0000,0x0001);
 Delay(5); // delay 50 ms
 DeviceCode = LCD_ReadReg(0x0000);  
 if(DeviceCode==0x9325||DeviceCode==0x9328)//ILI9325
 {
    LCD_WriteReg(0x00e7,0x0010);     
        LCD_WriteReg(0x0000,0x0001);//开启内部时钟
        LCD_WriteReg(0x0001,0x0100);    
        LCD_WriteReg(0x0002,0x0700);//电源开启                   
  //LCD_WriteReg(0x0003,(1<<3)|(1<<4) );  //65K  RGB
  //DRIVE TABLE(寄存器 03H)
  //BIT3=AM BIT4:5=ID0:1
  //AM ID0 ID1   FUNCATION
  // 0  0   0    R->L D->U
  // 1  0   0    D->U R->L
  // 0  1   0    L->R D->U
  // 1  1   0    D->U L->R
  // 0  0   1    R->L U->D
  // 1  0   1    U->D R->L
  // 0  1   1    L->R U->D 正常就用这个.
  // 1  1   1    U->D L->R
        LCD_WriteReg(0x0003,(1<<12)|(3<<4)|(0<<3) );//65K   
        LCD_WriteReg(0x0004,0x0000);                                  
        LCD_WriteReg(0x0008,0x0207);           
        LCD_WriteReg(0x0009,0x0000);        
        LCD_WriteReg(0x000a,0x0000);//display setting        
        LCD_WriteReg(0x000c,0x0001);//display setting         
        LCD_WriteReg(0x000d,0x0000);//0f3c         
        LCD_WriteReg(0x000f,0x0000);
  //电源配置
        LCD_WriteReg(0x0010,0x0000);  
        LCD_WriteReg(0x0011,0x0007);
        LCD_WriteReg(0x0012,0x0000);                                                                
        LCD_WriteReg(0x0013,0x0000);                
        Delay(5);
        LCD_WriteReg(0x0010,0x1590);  
        LCD_WriteReg(0x0011,0x0227);
        Delay(5);
        LCD_WriteReg(0x0012,0x009c);                 
        Delay(5);
        LCD_WriteReg(0x0013,0x1900);  
        LCD_WriteReg(0x0029,0x0023);
        LCD_WriteReg(0x002b,0x000e);
        Delay(5);
        LCD_WriteReg(0x0020,0x0000);                                                           
        LCD_WriteReg(0x0021,0x013f);          
  Delay(5);
  //伽马校正
        LCD_WriteReg(0x0030,0x0007);
        LCD_WriteReg(0x0031,0x0707);  
        LCD_WriteReg(0x0032,0x0006);
        LCD_WriteReg(0x0035,0x0704);
        LCD_WriteReg(0x0036,0x1f04);
        LCD_WriteReg(0x0037,0x0004);
        LCD_WriteReg(0x0038,0x0000);       
        LCD_WriteReg(0x0039,0x0706);    
        LCD_WriteReg(0x003c,0x0701);
        LCD_WriteReg(0x003d,0x000f);
        Delay(5);
        LCD_WriteReg(0x0050,0x0000); //水平GRAM起始位置
        LCD_WriteReg(0x0051,0x00ef); //水平GRAM终止位置                   
        LCD_WriteReg(0x0052,0x0000); //垂直GRAM起始位置                   
        LCD_WriteReg(0x0053,0x013f); //垂直GRAM终止位置 
       
        LCD_WriteReg(0x0060,0xa700);       
        LCD_WriteReg(0x0061,0x0001);
        LCD_WriteReg(0x006a,0x0000);
        LCD_WriteReg(0x0080,0x0000);
        LCD_WriteReg(0x0081,0x0000);
        LCD_WriteReg(0x0082,0x0000);
        LCD_WriteReg(0x0083,0x0000);
        LCD_WriteReg(0x0084,0x0000);
        LCD_WriteReg(0x0085,0x0000);
     
        LCD_WriteReg(0x0090,0x0010);    
        LCD_WriteReg(0x0092,0x0000); 
        LCD_WriteReg(0x0093,0x0003);
        LCD_WriteReg(0x0095,0x0110);
        LCD_WriteReg(0x0097,0x0000);       
        LCD_WriteReg(0x0098,0x0000); 
        //开启显示设置   
        LCD_WriteReg(0x0007,0x0133);  
        LCD_WriteReg(0x0020,0x0000);                                                           
        LCD_WriteReg(0x0021,0x013f);
 }
 else if(DeviceCode==0x9320||DeviceCode==0x9300)
 {
  LCD_WriteReg(0x00,0x0000);
  LCD_WriteReg(0x01,0x0100); //Driver Output Contral.
  LCD_WriteReg(0x02,0x0700); //LCD Driver Waveform Contral.
  //LCD_WriteReg(0x03,0x1030);//Entry Mode Set.
  LCD_WriteReg(0x03,0x1018); //Entry Mode Set.
 
  LCD_WriteReg(0x04,0x0000); //Scalling Contral.
  LCD_WriteReg(0x08,0x0202); //Display Contral 2.(0x0207)
  LCD_WriteReg(0x09,0x0000); //Display Contral 3.(0x0000)
  LCD_WriteReg(0x0a,0x0000); //Frame Cycle Contal.(0x0000)
  LCD_WriteReg(0x0c,(1<<0)); //Extern Display Interface Contral 1.(0x0000)
  LCD_WriteReg(0x0d,0x0000); //Frame Maker Position.
  LCD_WriteReg(0x0f,0x0000); //Extern Display Interface Contral 2.    
  Delay(5);
  LCD_WriteReg(0x07,0x0101); //Display Contral.
  Delay(5);          
  LCD_WriteReg(0x10,(1<<12)|(0<<8)|(1<<7)|(1<<6)|(0<<4)); //Power Control 1.(0x16b0)
  LCD_WriteReg(0x11,0x0007);        //Power Control 2.(0x0001)
  LCD_WriteReg(0x12,(1<<8)|(1<<4)|(0<<0));    //Power Control 3.(0x0138)
  LCD_WriteReg(0x13,0x0b00);        //Power Control 4.
  LCD_WriteReg(0x29,0x0000);        //Power Control 7.
 
  LCD_WriteReg(0x2b,(1<<14)|(1<<4));    
  LCD_WriteReg(0x50,0); //Set X Star
  //水平GRAM终止位置Set X End.
  LCD_WriteReg(0x51,239); //Set Y Star
  LCD_WriteReg(0x52,0); //Set Y End.t.
  LCD_WriteReg(0x53,319); //
 
  LCD_WriteReg(0x60,0x2700); //Driver Output Control.
  LCD_WriteReg(0x61,0x0001); //Driver Output Control.
  LCD_WriteReg(0x6a,0x0000); //Vertical Srcoll Control.
 
  LCD_WriteReg(0x80,0x0000); //Display Position? Partial Display 1.
  LCD_WriteReg(0x81,0x0000); //RAM Address Start? Partial Display 1.
  LCD_WriteReg(0x82,0x0000); //RAM Address End-Partial Display 1.
  LCD_WriteReg(0x83,0x0000); //Displsy Position? Partial Display 2.
  LCD_WriteReg(0x84,0x0000); //RAM Address Start? Partial Display 2.
  LCD_WriteReg(0x85,0x0000); //RAM Address End? Partial Display 2.
 
  LCD_WriteReg(0x90,(0<<7)|(16<<0)); //Frame Cycle Contral.(0x0013)
  LCD_WriteReg(0x92,0x0000); //Panel Interface Contral 2.(0x0000)
  LCD_WriteReg(0x93,0x0001); //Panel Interface Contral 3.
  LCD_WriteReg(0x95,0x0110); //Frame Cycle Contral.(0x0110)
  LCD_WriteReg(0x97,(0<<8)); //
  LCD_WriteReg(0x98,0x0000); //Frame Cycle Contral.   
  LCD_WriteReg(0x07,0x0173); //(0x0173)
 }
 
 else if(DeviceCode==0x1505)
 {
  // second release on 3/5  ,luminance is acceptable,water wave appear during camera preview
        LCD_WriteReg(0x0007,0x0000);
        Delay(5);
        LCD_WriteReg(0x0012,0x011C);//0x011A   why need to set several times?
        LCD_WriteReg(0x00A4,0x0001);//NVM 
        LCD_WriteReg(0x0008,0x000F);
        LCD_WriteReg(0x000A,0x0008);
        LCD_WriteReg(0x000D,0x0008);    
    //伽马校正
        LCD_WriteReg(0x0030,0x0707);
        LCD_WriteReg(0x0031,0x0007); //0x0707
        LCD_WriteReg(0x0032,0x0603);
        LCD_WriteReg(0x0033,0x0700);
        LCD_WriteReg(0x0034,0x0202);
        LCD_WriteReg(0x0035,0x0002); //?0x0606
        LCD_WriteReg(0x0036,0x1F0F);
        LCD_WriteReg(0x0037,0x0707); //0x0f0f  0x0105
        LCD_WriteReg(0x0038,0x0000);
        LCD_WriteReg(0x0039,0x0000);
        LCD_WriteReg(0x003A,0x0707);
        LCD_WriteReg(0x003B,0x0000); //0x0303
        LCD_WriteReg(0x003C,0x0007); //?0x0707
        LCD_WriteReg(0x003D,0x0000); //0x1313//0x1f08
        Delay(5);
        LCD_WriteReg(0x0007,0x0001);
        LCD_WriteReg(0x0017,0x0001);//开启电源
        Delay(5);
    //电源配置
        LCD_WriteReg(0x0010,0x17A0);
        LCD_WriteReg(0x0011,0x0217);//reference voltage VC[2:0]   Vciout = 1.00*Vcivl
        LCD_WriteReg(0x0012,0x011E);//0x011c  //Vreg1out = Vcilvl*1.80   is it the same as Vgama1out ?
        LCD_WriteReg(0x0013,0x0F00);//VDV[4:0]-->VCOM Amplitude VcomL = VcomH - Vcom Ampl
        LCD_WriteReg(0x002A,0x0000); 
        LCD_WriteReg(0x0029,0x000A);//0x0001F  Vcomh = VCM1[4:0]*Vreg1out    gate source voltage??
        LCD_WriteReg(0x0012,0x013E);// 0x013C  power supply on
        //Coordinates Control//
        LCD_WriteReg(0x0050,0x0000);//0x0e00
        LCD_WriteReg(0x0051,0x00EF);
        LCD_WriteReg(0x0052,0x0000);
        LCD_WriteReg(0x0053,0x013F);
     //Pannel Image Control//
        LCD_WriteReg(0x0060,0x2700);
        LCD_WriteReg(0x0061,0x0001);
        LCD_WriteReg(0x006A,0x0000);
        LCD_WriteReg(0x0080,0x0000);
     //Partial Image Control//
        LCD_WriteReg(0x0081,0x0000);
        LCD_WriteReg(0x0082,0x0000);
        LCD_WriteReg(0x0083,0x0000);
        LCD_WriteReg(0x0084,0x0000);
        LCD_WriteReg(0x0085,0x0000);
    //Panel Interface Control//
        LCD_WriteReg(0x0090,0x0013);//0x0010 frenqucy
        LCD_WriteReg(0x0092,0x0300);
        LCD_WriteReg(0x0093,0x0005);
        LCD_WriteReg(0x0095,0x0000);
        LCD_WriteReg(0x0097,0x0000);
        LCD_WriteReg(0x0098,0x0000);
 
        LCD_WriteReg(0x0001,0x0100);
        LCD_WriteReg(0x0002,0x0700);
        LCD_WriteReg(0x0003,0x1030);
        LCD_WriteReg(0x0004,0x0000);
        LCD_WriteReg(0x000C,0x0000);
        LCD_WriteReg(0x000F,0x0000);
        LCD_WriteReg(0x0020,0x0000);
        LCD_WriteReg(0x0021,0x0000);
        LCD_WriteReg(0x0007,0x0021);
        Delay(20);
        LCD_WriteReg(0x0007,0x0061);
        Delay(20);
        LCD_WriteReg(0x0007,0x0173);
        Delay(20);
 }       
 else if(DeviceCode==0x8989)
 {
  LCD_WriteReg(0x0000,0x0001);Delay(5);//打开晶振
     LCD_WriteReg(0x0003,0xA8A4);Delay(5);//0xA8A4
     LCD_WriteReg(0x000C,0x0000);Delay(5);   
     LCD_WriteReg(0x000D,0x080C);Delay(5);   
     LCD_WriteReg(0x000E,0x2B00);Delay(5);   
     LCD_WriteReg(0x001E,0x00B0);Delay(5);   
     LCD_WriteReg(0x0001,0x2B3F);Delay(5);//驱动输出控制320*240  0x6B3F
     LCD_WriteReg(0x0002,0x0600);Delay(5);
     LCD_WriteReg(0x0010,0x0000);Delay(5);
     LCD_WriteReg(0x0011,0x6070);Delay(5);//定义数据格式  16位色   横屏 0x6058
     LCD_WriteReg(0x0005,0x0000);Delay(5);
     LCD_WriteReg(0x0006,0x0000);Delay(5);
     LCD_WriteReg(0x0016,0xEF1C);Delay(5);
     LCD_WriteReg(0x0017,0x0003);Delay(5);
     LCD_WriteReg(0x0007,0x0233);Delay(5);//0x0233      
     LCD_WriteReg(0x000B,0x0000);Delay(5);
     LCD_WriteReg(0x000F,0x0000);Delay(5);//扫描开始地址
     LCD_WriteReg(0x0041,0x0000);Delay(5);
     LCD_WriteReg(0x0042,0x0000);Delay(5);
     LCD_WriteReg(0x0048,0x0000);Delay(5);
     LCD_WriteReg(0x0049,0x013F);Delay(5);
     LCD_WriteReg(0x004A,0x0000);Delay(5);
     LCD_WriteReg(0x004B,0x0000);Delay(5);
     LCD_WriteReg(0x0044,0xEF00);Delay(5);
     LCD_WriteReg(0x0045,0x0000);Delay(5);
     LCD_WriteReg(0x0046,0x013F);Delay(5);
     LCD_WriteReg(0x0030,0x0707);Delay(5);
     LCD_WriteReg(0x0031,0x0204);Delay(5);
     LCD_WriteReg(0x0032,0x0204);Delay(5);
     LCD_WriteReg(0x0033,0x0502);Delay(5);
     LCD_WriteReg(0x0034,0x0507);Delay(5);
     LCD_WriteReg(0x0035,0x0204);Delay(5);
     LCD_WriteReg(0x0036,0x0204);Delay(5);
     LCD_WriteReg(0x0037,0x0502);Delay(5);
     LCD_WriteReg(0x003A,0x0302);Delay(5);
     LCD_WriteReg(0x003B,0x0302);Delay(5);
     LCD_WriteReg(0x0023,0x0000);Delay(5);
     LCD_WriteReg(0x0024,0x0000);Delay(5);
     LCD_WriteReg(0x0025,0x8000);Delay(5);
     LCD_WriteReg(0x004f,0);        //行首址0
     LCD_WriteReg(0x004e,0);        //列首址0
 }      
 Delay(5000); 
 LCD_Clear(WHITE);
}   
//清屏函数
//Color:要清屏的填充色
void LCD_Clear(u16 Color)
{
 u32 index="0";     
 LCD_SetCursor(0x00,0x0000);//设置光标位置
 LCD_WriteRAM_Prepare();     //开始写入GRAM    
 for(index=0;index<76800;index++)
 {
  LCD->LCD_RAM=Color;
  //delay_ms(2);
 }

//在指定区域内填充指定颜色
//区域大小:
//  (xend-xsta)*(yend-ysta)
void LCD_Fill(u8 xsta,u16 ysta,u8 xend,u16 yend,u16 color)
{                   
    u32 n;
 //设置窗口          
 LCD_WriteReg(R80, xsta); //水平方向GRAM起始地址
 LCD_WriteReg(R81, xend); //水平方向GRAM结束地址
 LCD_WriteReg(R82, ysta); //垂直方向GRAM起始地址
 LCD_WriteReg(R83, yend); //垂直方向GRAM结束地址 
 LCD_SetCursor(xsta,ysta);//设置光标位置 
 LCD_WriteRAM_Prepare();  //开始写入GRAM         
 n=(u32)(yend-ysta+1)*(xend-xsta+1);   
 while(n--){LCD->LCD_RAM=color;}//显示所填充的颜色.
 //恢复设置
 LCD_WriteReg(R80, 0x0000); //水平方向GRAM起始地址
 LCD_WriteReg(R81, 0x00EF); //水平方向GRAM结束地址
 LCD_WriteReg(R82, 0x0000); //垂直方向GRAM起始地址
 LCD_WriteReg(R83, 0x013F); //垂直方向GRAM结束地址    

//画线
//x1,y1:起点坐标
//x2,y2:终点坐标 
void LCD_DrawLine(u8 x1, u16 y1, u8 x2, u16 y2)
{
    u16 x, y, t;
 if((x1==x2)&&(y1==y2))LCD_DrawPoint(x1, y1);
 else if(abs(y2-y1)>abs(x2-x1))//斜率大于1
 {
  if(y1>y2)
  {
   t=y1;
   y1=y2;
   y2=t;
   t=x1;
   x1=x2;
   x2=t;
  }
  for(y=y1;y<y2;y++)//以y轴为基准
  {
   x=(u32)(y-y1)*(x2-x1)/(y2-y1)+x1;
   LCD_DrawPoint(x, y); 
  }
 }
 else     //斜率小于等于1
 {
  if(x1>x2)
  {
   t=y1;
   y1=y2;
   y2=t;
   t=x1;
   x1=x2;
   x2=t;
  }  
  for(x=x1;x<=x2;x++)//以x轴为基准
  {
   y =(u32)(x-x1)*(y2-y1)/(x2-x1)+y1;
   LCD_DrawPoint(x,y);
  }
 }
}   
//画矩形
void LCD_DrawRectangle(u8 x1, u16 y1, u8 x2, u16 y2)
{
 LCD_DrawLine(x1,y1,x2,y1);
 LCD_DrawLine(x1,y1,x1,y2);
 LCD_DrawLine(x1,y2,x2,y2);
 LCD_DrawLine(x2,y1,x2,y2);
}
//在指定位置画一个指定大小的圆
//(x,y):中心点
//r    :半径
void Draw_Circle(u8 x0,u16 y0,u8 r)
{
 int a,b;
 int di;
 a=0;b=r;  
 di=3-(r<<1);             //判断下个点位置的标志
 while(a<=b)
 {
  LCD_DrawPoint(x0-b,y0-a);             //3          
  LCD_DrawPoint(x0+b,y0-a);             //0          
  LCD_DrawPoint(x0-a,y0+b);             //1      
  LCD_DrawPoint(x0-b,y0-a);             //7          
  LCD_DrawPoint(x0-a,y0-b);             //2            
  LCD_DrawPoint(x0+b,y0+a);             //4              
  LCD_DrawPoint(x0+a,y0-b);             //5
  LCD_DrawPoint(x0+a,y0+b);             //6
  LCD_DrawPoint(x0-b,y0+a);            
  a++;
  //使用Bresenham算法画圆    
  if(di<0)di +=4*a+6;  
  else
  {
   di+=10+4*(a-b);  
   b--;
  }
  LCD_DrawPoint(x0+a,y0+b);
 }
}
//在指定位置显示一个字符
//x:0~234
//y:0~308
//num:要显示的字符:" "--->"~"
//size:字体大小 12/16
//mode:叠加方式(1)还是非叠加方式(0)
void LCD_ShowChar(u8 x,u16 y,u8 num,u8 size,u8 mode)
{      
#define MAX_CHAR_POSX 232
#define MAX_CHAR_POSY 304
    u8 temp;
    u8 pos,t;     
    if(x>MAX_CHAR_POSX||y>MAX_CHAR_POSY)return;    
 //设置窗口          
 LCD_WriteReg(R80,x);           //水平方向GRAM起始地址
 LCD_WriteReg(R81,x+(size/2-1));//水平方向GRAM结束地址
 LCD_WriteReg(R82,y);           //垂直方向GRAM起始地址
 LCD_WriteReg(R83,y+size-1);    //垂直方向GRAM结束地址 
 LCD_SetCursor(x,y);            //设置光标位置 
 LCD_WriteRAM_Prepare();        //开始写入GRAM   
 num=num-' ';//得到偏移后的值
 if(!mode) //非叠加方式
 {
  for(pos=0;pos<size;pos++)
  {
   if(size==12)temp=asc2_1206[num][pos];//调用1206字体
   else temp="asc2"_1608[num][pos];   //调用1608字体
   for(t=0;t<size/2;t++)
      {                
          if(temp&0x01)LCD->LCD_RAM=POINT_COLOR;
          else LCD->LCD_RAM=BACK_COLOR;    
          temp>>=1;
      }
  } 
 }else//叠加方式
 {
  for(pos=0;pos<size;pos++)
  {
   if(size==12)temp=asc2_1206[num][pos];//调用1206字体
   else temp="asc2"_1608[num][pos];   //调用1608字体
   for(t=0;t<size/2;t++)
      {                
          if(temp&0x01)LCD_DrawPoint(x+t,y+pos);//画一个点    
          temp>>=1;
      }
  }
 }    
 //恢复窗体大小 
 LCD_WriteReg(R80, 0x0000); //水平方向GRAM起始地址
 LCD_WriteReg(R81, 0x00EF); //水平方向GRAM结束地址
 LCD_WriteReg(R82, 0x0000); //垂直方向GRAM起始地址
 LCD_WriteReg(R83, 0x013F); //垂直方向GRAM结束地址

//m^n函数
u32 mypow(u8 m,u8 n)
{
 u32 result="1"; 
 while(n--)result*=m;   
 return result;
}     
//显示2个数字
//x,y :起点坐标 
//len :数字的位数
//size:字体大小
//mode:模式 0,填充模式;1,叠加模式
//num:数值(0~65536); 
void LCD_ShowNum(u8 x,u16 y,u16 num,u8 len,u8 size)
{          
 u8 t,temp;        
 for(t=0;t<len;t++)
 {
  temp=(num/mypow(10,len-t-1))%10;
   LCD_ShowChar(x+(size/2)*t,y,temp+'0',size,0);
 }
}
//显示字符串
//x,y:起点坐标 
//*p:字符串起始地址
//用16字体
void LCD_ShowString(u8 x,u16 y,const u8 *p)
{        
    while(*p!='\0')
    {      
        if(x>MAX_CHAR_POSX){x=0;y+=16;}
        if(y>MAX_CHAR_POSY){y=x=0;LCD_Clear(WHITE);}
        LCD_ShowChar(x,y,*p,16,0);
        x+=8;
        p++;
    } 
}

主函数代码如下:

#include <stm32f10x_lib.h>
#include "sys.h"
#include "usart.h"  
#include "delay.h"
#include "lcd.h"   
//STMSKY开发板 2.8寸液晶测试代码
//正点原子@深圳南山
//2009.12.31    
      
int main(void)
{
    u8 x="0";   
 Stm32_Clock_Init(9);//系统时钟设置
 delay_init(72);  //延时初始化
 uart_init(72,9600); //串口1初始化    
 LCD_Init();   //初始化液晶   
   while(1)
 {  
  switch(x)
  {
   case 0:LCD_Clear(YELLOW);break;
   case 1:LCD_Clear(GRAY);break;
   case 2:LCD_Clear(BLUE);break;
   case 3:LCD_Clear(RED);break;
   case 4:LCD_Clear(MAGENTA);break;
   case 5:LCD_Clear(GREEN);break;
   case 6:LCD_Clear(CYAN);break;
  }
  POINT_COLOR=RED;  
  LCD_ShowString(30,50,"STMSKY ^_^"); 
  LCD_ShowString(30,70,"2.8'LCD TEST"); 
  LCD_ShowString(30,90,"ATOM@HYW");
  LCD_ShowString(30,110,"2009/12/31");          
     x++;
  if(x==7)x=0;     
  delay_ms(1000); 
 } 
}

源码:

http://space.ednchina.com/upload/2009/12/31/3504b6a6-ad8d-4f74-945a-7ccb4f1b5096.rar

显示效果:

点击看大图

点击看大图

点击看大图

点击看大图

点击看大图

点击看大图

 

 

 

 

 

 

 

 

 

 

 

 

 

系统分类: ARM  |  用户分类: STM32学习  |  标签: 2.8寸LCD STM32ZET6 FSMC 液晶显示  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(514) | 回复(3)

发表于 2009/12/25 19:00:53

0

关于投票

跟我学STM32之3 串口使用

串口能给我们编程调试带来很大帮助,STM32的串口使用起来也很简单,参考官方代码,然后对照STM32手册,就能找到相关寄存器设置,以及设置的先后顺序.
以下是我写的对串口操作的c文件,串口1测试无问题,串口2,3还未测试,各位可以根据自己的需要对void uart_init(u32 pclk2,u32 bound)里面的相应寄存器做修改.如果有问题请通知我.

#include "sys.h"
#include "usart.h"
//正点原子@HYW
//2009/12/08
//V1.3
//支持适应不同频率下的串口波特率设置.
   
#ifdef __GNUC__         
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
//重定义C语言库函数printf到串口1
//CHECK OK
//091209
PUTCHAR_PROTOTYPE
{           
USART1->DR=ch;//写一个字符到串口1   
   while(1)//循环发送,直到发送完毕
{
  if(USART1->SR&0X40)break;//如果发送完了,跳出
};   
   return ch;
}   
//中断优先级管理/开启
//CHECK OK
//091209   
void NVIC_Configuration(void)
{
  MY_NVIC_PriorityGroupConfig(0);//设置分组0  全部4位都是响应优先级        
MY_NVIC_Init(0,1,USART1_IRQChannel,0);//响应优先级1,抢占优先级0(未配置)            
}
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误   
u8 rebuffer[14];//接收缓冲  
u8 recount="0";   //接收完全     
void USART1_IRQHandler(void)
{
u8 res;     
if(USART1->SR&(1<<5))//接收到数据
{  
  res=USART1->DR;         
  if(recount<14&&res>47&&res<58)//仅仅接收数据 (0~9)
  {
   rebuffer[recount]=res-'0';//得到ASCII
   recount++;
  }                  
}  
}            
//初始化IO 串口1
//pclk2:CLK2时钟频率(Mhz)
//bound:波特率
//CHECK OK
//091209
void uart_init(u32 pclk2,u32 bound)
{   
float temp;
u16 mantissa;
u16 fraction;   
temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV
mantissa=temp;     //得到整数部分
fraction=(temp-mantissa)*16; //得到小数部分  
    mantissa<<=4;
mantissa+=fraction;
RCC->APB2ENR|=1<<2;   //使能PORTA口时钟  
RCC->APB2ENR|=1<<14;  //使能串口时钟
GPIOA->CRH=0X444444B4;//IO状态设置
   
RCC->APB2RSTR|=1<<14;   //复位串口1
RCC->APB2RSTR&=~(1<<14);//停止复位        
//波特率设置
  USART1->BRR=mantissa; // 波特率设置  
USART1->CR1|=0X200C;  //1位停止,无校验位.
//使能接收中断
USART1->CR1|=1<<8;    //PE中断使能
USART1->CR1|=1<<5;    //接收缓冲区非空中断使能
NVIC_Configuration(); //中断管理,不开启
}

源码:http://space.ednchina.com/upload/2009/12/25/bd9ad12f-31f2-4ab2-b6cf-26ab646fab1c.rar

上位机接收到的数据:

点击看大图

系统分类: ARM  |  用户分类: STM32学习  |  标签: STM32 串口使用 非库函数  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(338) | 回复(2)

发表于 2009/12/23 20:49:23

0

关于投票

跟我学STM32之2 按键输入

之前讲了STM32的初始化,并点亮了LED.现在来做按键输入基本和点亮LED差不多只是把输出改成输入.
以下是按键输入,按键处理部分的代码.
#include <stm32f10x_lib.h>
#include "key.h"
#include "delay.h"
//正点原子
//2009/12/23   
//按键输入
#define KEY1 (1<<6) //PC6
#define KEY2 (1<<7) //PC7
#define KEY3 (1<<8) //PC8
//按键初始化函数
//PC.6.7.8 设置成带上拉的输入
void key_init(void)
{
RCC->APB2ENR|=1<<4;    //使能PORTC时钟
GPIOC->CRL&=0X00FFFFFF;//PC6.7设置成输入   
GPIOC->CRL|=0X88000000;  

GPIOC->CRH&=0XFFFFFFF0;//PC8,设置成输入
GPIOC->CRH|=0X08;
               
    GPIOC->ODR|=0X1C0;    //PC 6 7 8 上拉输入
}  
//按键处理函数
u8 key_scan(void)
{  
static u8 key_up=1;//按键按松开标志
u16 key_val=(GPIOC->IDR>>6)&0X07;   
if(key_up&&key_val<7)//有按键按下
{
  delay_ms(10);//去抖动
  key_up=0;
   key_val=(GPIOC->IDR>>6)&0X07;  
  switch(key_val)
  {
   case 6: return 1;
   case 5: return 2;
   case 3: return 3;
  }
}else if(key_val==7)key_up=1;   
return 0;// 无按键按下
}
主函数:
#include <stm32f10x_lib.h>
#include "sys.h"
#include "usart.h"  
#include "delay.h"  
#include "key.h"  
#include "led.h"
//正点原子
//2009/12/23      
int main(void)
{
u8 time="0";   
u8 L0=0,L1=0,L2=0;
Stm32_Clock_Init(9);//72M
delay_init(72);     //延时初始化
//uart_init(72,9600); //设置波特率
led_init();   
    while (1)
    {
  switch(key_scan())
  {
   case 1:LED0_SET(L0);L0=!L0;break;
   case 2:LED1_SET(L1);L1=!L1;break;
   case 3:LED2_SET(L2);L2=!L2;break;
  }        
  time++;
  if(time==100)LED3_SET(0);
     else if(time==200)
  {
   LED3_SET(1);
   time=0;
  }
  delay_ms(5);               
    }
}

源码:

http://space.ednchina.com/upload/2009/12/23/8acf1ca3-92a7-4d25-a318-92ce58e8016b.rar

针对STMSKY网络开发板的代码:

http://space.ednchina.com/upload/2009/12/31/1ad6e001-94bd-4c71-b679-10e7e39cf914.rar

按键输入效果:

点击看大图

系统分类: ARM  |  用户分类: STM32学习  |  标签: STM32 按键输入 非库函数  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(235) | 回复(0)

发表于 2009/12/22 20:33:21

0

关于投票

跟我学STM32之1 跑马灯

写在前面的话
    自从去年接触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);         
    }
}


至此,一个跑马灯程序就完成了.

源码:http://space.ednchina.com/upload/2009/12/22/5bbbfc5d-2aec-4794-aec3-7110ffecc983.rar

 

这两天把STMSKY的板子焊接好了,以后代码就基于这个平台了

新代码:http://space.ednchina.com/upload/2009/12/31/bcceda0a-b9ea-4668-896b-a2f0ee475589.rar

这里代码做了点修改,下面是运行结果:

可以看到红绿蓝三个灯以此点亮.

点击看大图

点击看大图

点击看大图

系统分类: ARM  |  用户分类: STM32学习  |  标签: 跑马灯 STM32 非库函数  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(487) | 回复(0)

发表于 2009/6/7 0:17:22

1

关于投票

基于STM32的多功能MP3播放器(毕设)

花了近三个月的时间做的毕业设计,直到前几天才在算基本完成了。这几天忙着毕业论文,先上图顺便上传现在使用的软件代码。STM32+RVMDK。
本MP3有的功能:
●MP3播放功能,支持MP3/WAV/WMA/MIDI播放,支持快进,快退,歌词显示支持[XX:XX:XX]/[XX:XX.XX]/[XX:XX],支持多句歌词共用tag
●收音机功能,支持自动搜台,FM76~108M,自动存台
●图片播放功能,支持16bit,24bit,32bit,任意大小的BMP图片浏览,以及JPEG/JPG图片的浏览(只要是格式正确,大小不限)
●温度计功能,DS18B20的
●彩色台灯功能
●功率放大功能
●万历年功能,支持阳历,阴历,周和节气显示
●闹钟功能,支持八个闹钟,任意闹铃方式,支持MP3和收音机作为闹钟,灵感来自山寨Iphone的闹钟。
●游戏功能,拼图游戏,三种难度
●电子书功能

点击看大图
 (原文件名:IMG_3856.jpg) 


点击看大图
 (原文件名:IMG_3857.jpg) 


点击看大图
 (原文件名:IMG_3859.jpg) 


点击看大图
 (原文件名:IMG_3862.jpg) 


点击看大图
 (原文件名:IMG_3863.jpg) 


点击看大图
 (原文件名:IMG_3866.jpg) 


点击看大图
 (原文件名:IMG_3867.jpg) 


点击看大图
 (原文件名:IMG_3868.jpg) 


点击看大图
 (原文件名:IMG_3869.jpg) 


点击看大图
 (原文件名:IMG_3870.jpg) 


点击看大图
 (原文件名:IMG_3872.jpg) 


点击看大图
 (原文件名:IMG_3873.jpg) 

点击看大图
 (原文件名:IMG_3875.jpg) 


点击看大图
 (原文件名:IMG_3876.jpg) 


点击看大图
 (原文件名:IMG_3877.jpg) 


点击看大图
 (原文件名:IMG_3878.jpg) 


点击看大图
 (原文件名:IMG_3879.jpg) 


点击看大图
 (原文件名:IMG_3881.jpg) 


点击看大图
 (原文件名:IMG_3882.jpg) 


点击看大图
 (原文件名:IMG_3883.jpg) 


点击看大图
 (原文件名:IMG_3884.jpg) 


点击看大图
 (原文件名:IMG_3885.jpg) 


点击看大图
 (原文件名:IMG_3886.jpg) 


点击看大图
 (原文件名:IMG_3887.jpg) 

点击看大图
 (原文件名:IMG_3888.jpg) 


点击看大图
 (原文件名:IMG_3890.jpg) 


点击看大图
 (原文件名:IMG_3891.jpg) 


点击看大图
 (原文件名:IMG_3894.jpg) 


点击看大图
 (原文件名:IMG_3893.jpg) 


点击看大图
 (原文件名:IMG_3896.jpg) 


点击看大图
 (原文件名:IMG_3897.jpg) 


点击看大图
 (原文件名:IMG_3898.jpg) 


点击看大图
 (原文件名:IMG_3900.jpg) 


点击看大图
 (原文件名:IMG_3901.jpg) 


点击看大图
 (原文件名:IMG_3902.jpg) 


点击看大图
 (原文件名:IMG_3903.jpg) 


点击看大图
 (原文件名:IMG_3904.jpg) 


点击看大图
 (原文件名:IMG_3906.jpg) 


点击看大图
 (原文件名:IMG_3908.jpg) 


点击看大图
 (原文件名:IMG_3909.jpg) 


点击看大图
 (原文件名:IMG_3911.jpg) 


点击看大图
 (原文件名:IMG_3912.jpg) 


点击看大图
 (原文件名:IMG_3913.jpg) 


点击看大图
 (原文件名:IMG_3914.jpg) 


点击看大图
 (原文件名:IMG_3915.jpg) 


点击看大图
 (原文件名:IMG_3916.jpg) 


点击看大图
 (原文件名:IMG_3917.jpg) 


点击看大图
 (原文件名:IMG_3918.jpg) 


点击看大图
 (原文件名:IMG_3920.jpg) 


点击看大图
 (原文件名:IMG_3922.jpg) 


点击看大图
 (原文件名:IMG_3924.jpg) 


点击看大图
 (原文件名:IMG_3925.jpg) 


点击看大图
 (原文件名:IMG_3927.jpg) 


点击看大图
 (原文件名:IMG_3928.jpg) 


点击看大图
 (原文件名:IMG_3930.jpg) 


点击看大图
 (原文件名:IMG_3931.jpg) 


点击看大图
 (原文件名:IMG_3932.jpg) 


点击看大图
 (原文件名:IMG_3933.jpg) 


点击看大图
 (原文件名:IMG_3934.jpg) 


点击看大图
 (原文件名:IMG_3935.jpg) 


点击看大图
 (原文件名:IMG_3937.jpg) 


点击看大图
 (原文件名:IMG_3938.jpg) 


点击看大图
 (原文件名:IMG_3939.jpg) 


点击看大图
 (原文件名:IMG_3941.jpg) 


点击看大图
 (原文件名:IMG_3942.jpg) 


点击看大图
 (原文件名:IMG_3943.jpg) 


点击看大图
 (原文件名:IMG_3946.jpg) 


点击看大图
 (原文件名:IMG_3951.jpg) 


点击此处打开 ourdev_451253.jpg(文件大小:407K,只有400K以内的图片才能直接显示) (原文件名:IMG_3952.jpg) 
点击看大图
 (原文件名:IMG_3953.jpg) 


代码由于这个论坛有1m的限制,就不上传了。想下载的去:http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=3384713&bbs_page_no=1&search_mode=3&search_text=liujun6037&bbs_id=9999

系统分类: ARM  |  用户分类: STM32学习  |  标签: STM32 FAT JPEG/BMP/JPG 收音机 MP3 歌词显示 DS18B20 FM24C16  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(1222) | 回复(4)

发表于 2008/12/24 8:59:33

2

关于投票

STM32窗口看门狗使用(WWDG)

    上次发现WWDG不能用,准确的说是不能仿真.所以就没有弄了.前几天,没事干的时候把它再弄了一下,突然发现keil的仿真中WWDG->CR寄存器的值能动了,一下就来劲了.不过后来发现又不行了.于是又看书,看究竟是怎么搞的.后来发现在寄存器描述里面提到,在发生wwdg复位之后,一定要硬件复位,EWI标志才会清除,不过这个和WWDG->CR计数器的关系不大,看资料说WWDG->CR是只要开启,就会进行自减计数的.

   keil不知道能不能仿真硬件复位.不过照这样的仿真结果,应该是keil的仿真有问题的.所以就按IWDG的思路写了代码:

int main(void)//GPIO
{       
    Stm32_Clock_Init();//系统时钟设置      
    led_init();
    delay_init(72);//72M系统时钟
    delay_ms(300);
    wwdg_init();   //配置并使能WWDG   
    while (1)
    {       
         LED0_SET(0);
         delay_us(500000);//在这里系统重启          
    }     
}
 

直接刷stm32.发现LED亮一下就不亮了,估计是发生了重启,然后我的BOOT设置还是在串口下载模式,于是吧boot改了,发现整个就运行起来了,灯一闪一闪的...

     证明我的WWDG设置是正确的,而keil仿真,则出不了结果.所以提醒网友在使用wwdg的时候,keil仿真出不了,但是实际只要你的寄存器设置正确了,还是会跑的.也说明了一个仿真,不是万能的,啥都得实际验证才能算数.想起毛爷爷一句话:实践是检验真理的唯一标准.

附上wwdg的设置头函数

#ifndef __WWDG_H
#define __WWDG_H
//WWDG使用
//下载完后,把BOOT0改为低电平,
//并按复位键后,才能看到现象!!
//正点原子@SCUT
//2008/12/19
//V1.0
//复位时间59ms左右.
void wwdg_init(void)
{
 RCC->APB1RSTR|=1<<11; //复位wwdg
 RCC->APB1RSTR&=~(1<<11);

 RCC->APB1ENR|=1<<11; //使能wwdg时钟

 WWDG->CFR|=3<<7;        //PCLK1/4096再8分频

 WWDG->CFR|=80;      //设定窗口值为80      
 WWDG->CR|=1<<7;   //使能WWDG看门狗
}
#endif 

 

    

系统分类: ARM  |  用户分类: STM32学习  |  标签: STM32 WWDG 窗口看门狗 KEIL仿真 RVMDK  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(1367) | 回复(3)

发表于 2008/12/17 10:50:26

5

关于投票

TFTLCD触摸屏测试(ADS7846/7843)

     STM32的板子做好之后,玩了也有一整了,昨天把触摸屏的代码搞定了,效果还算可以,实现了作图功能.算法相对简单,但是并不等于效果就不好.呵呵.

     基本思路:每次按下触摸屏,ADS7846的pen脚会拉低,STM32通过中断相应,然后在中断里面处理此次操作.对X,Y的坐标连续采样十次,不足十次的认为数据无效,不做任何操作.然后对十次数据进行排序,最后,取中间三次的数据进行平均,得到最终的X,Y坐标.然后在屏幕上对应这点而画点,因为,只要你的"笔"一直在屏幕上操作,PEN脚就一直是低的,所以,我在中断里面检测PEN脚,直到PEN脚变高,我才退出,这样就可以实现画图功能了.

点击看大图

效果图1

点击看大图

效果图2

点击看大图

效果图3

点击看大图

效果图4

点击看大图

效果图5

点击看大图

效果图6

附上代码(RVMDK):

http://space.ednchina.com/upload/2008/12/17/2f5b75db-51cc-400e-b7c9-7b79d6fe8728.rar

系统分类: ARM  |  用户分类: STM32学习  |  标签: TFTLCD 触摸屏 ADS7843 STM32F103RBT6 ADS7846  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(2906) | 回复(21)

发表于 2008/12/15 9:48:30

0

关于投票

STM32精确延时(非中断,非ST库函数) (续)

       昨天在做红外解码的时候,发现我先前那个延时函数在某些情况下会不可用.

      分析完之后,发现,该延时函数delay_ms(u32 Nms);delay_us(u32 Nus);在非中断函数里面运行很好.但是只要你在中断里面再调用delay_ms(u32 Nms);delay_us(u32 Nus);的话,就可能出问题了.

      原因如下:假设在处理延时1000ms,此时中断来了.那么你的程序就会打断延时,进入中断处理.但是很不幸,你在中断里面也调用了延时函数,假设是delay_us这个函数(delay_ms也一样).

void delay_us(u32 Nus)

 SysTick->LOAD=Nus*fac_us;       //时间加载     
 SysTick->CTRL|=0x01;            //开始倒数   
 while(!(SysTick->CTRL&(1<<16)));//等待时间到达
 SysTick->CTRL=0X00000000;       //关闭计数器
 SysTick->VAL=0X00000000;        //清空计数器    

        可以发现,在这个函数里面,你会先把LOAD寄存器重装,然后重新开始倒数.这时VAL中的值是未可知的,决定于先前在delay_ms里面的计时值.因为重载的发生是在VAL的值为0的条件下,所以除非VAL中的值为0,否则,在LOAD改变的时候VAL并不会重载.这样,就会导致延时的不准确(实际延时,就是上次的VAL减到0的时间).

       以上分析的是在中断里面可能出现延时不准.但是更严重的错误发生在退出中断后.在退出中断后,函数重新返回到延时1000ms的函数里面执行.可是,你从上面的代码可以知道,此时STRL已经控制计数器关闭了!这就导致了会死在delay_ms里面的

while(!(SysTick->CTRL&(1<<16)));//等待时间到达

这个时间是永远无法到达的.因为CTRL已经被清掉了,bit16无法被置1,所以无法退出该句代码!

    以上就是上次的延时函数存在的两个问题. 针对这两个问题,我把代码改了,可以实现中断调用,但是也存在一点小问题,就是跳出中断后当前的延时不再有效,也就是说,在发生中断的时候会有一次延时不准!(就是被中断打断的这次延时)

#ifndef __DELAY_H
#define __DELAY_H      
//使用SysTick的普通计数模式对延迟进行管理
//包括delay_us,delay_ms 
//正点原子@SCUT
//2008/12/14
//V1.2
//修正了中断中调用出现死循环的错误
//防止延时不准确,采用do while结构!
 
static u8  fac_us=0;//us延时倍乘数
static u16 fac_ms=0;//ms延时倍乘数
//初始化延迟函数
void delay_init(u8 SYSCLK)
{
 SysTick->CTRL&=0xfffffffb;//选择内部时钟 HCLK/8
 fac_us=SYSCLK/8;     
 fac_ms=(u16)fac_us*1000;
}           
//延时Nms
//注意Nms的范围
//Nms<=0xffffff*8/SYSCLK
//对72M条件下,Nms<=1864
void delay_ms(u16 nms)
{        
 u32 temp;    
 SysTick->LOAD=(u32)nms*fac_ms;//时间加载
 SysTick->VAL =0x00;           //清空计数器
 SysTick->CTRL=0x01 ;          //开始倒数 
 do
 {
  temp=SysTick->CTRL;
 }
 while(temp&0x01&&!(temp&(1<<16)));//等待时间到达  
 SysTick->CTRL=0x00;       //关闭计数器
 SysTick->VAL =0X00;       //清空计数器       
}  
//延时us          
void delay_us(u32 Nus)
{  
 u32 temp;      
 SysTick->LOAD=Nus*fac_us; //时间加载     
 SysTick->VAL=0x00;        //清空计数器
 SysTick->CTRL=0x01 ;      //开始倒数  
 do
 {
  temp=SysTick->CTRL;
 }
 while(temp&0x01&&!(temp&(1<<16)));//等待时间到达  
 SysTick->CTRL=0x00;       //关闭计数器
 SysTick->VAL =0X00;       //清空计数器    

#endif
    代码里面增加了对VAL的清空操作,以此来保证数据更新.在等待的时候,也加入了防错控制.CTRL的bit1必须为1,也就是计时器必须开启的情况下,延时函数才有效,否则,马上退出,这就避免了死循环,代价就是1次延时的不准确,不过一般来说还是可以接受的.

    其次还要注意读取CTRL的时候会把COUNTFLAG标志位在被读取之后自动清零,所以读取的时候注意不要把CTRL的读取顺序搞错了.

 

系统分类: ARM  |  用户分类: STM32学习  |  标签: STM32 SysTick 精确延时 非中断 不用ST库函数  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(1480) | 回复(0)

发表于 2008/12/14 19:35:08

2

关于投票

STM32精确延时(非中断,非ST库函数)

     前天学了下stm的systick,发现还满好用的,可以用来精确定时.以前在用CVAVR的时候发现里面的delay.h非常好用.于是,利用stm32的SysTick做了个精确的延时头函数.

     SysTick的配置在void delay_init(u8 SYSCLK);里面输入的参数SYSCLK是你配置的系统时钟,比如72M,我就调用delay_init(72);然后就完成了对SysTick的初始化设置.在后面调用delay_ms(u32 Nms);delay_us(u32 Nus);就可以得到很准确的延时.

注意:

1,delay_us(u32 Nus);在Nus值很小的时候,误差比较大,我仿真的时候delay_us(1);实际上得到的是延时了1.5us左右.理论上Nus的值越大,越准确.

2,delay_ms(u32 Nms);的参数不能太大!更具你系统时钟来确定.72M的时候Nms的最大值是1864.在其他晶振(<72M)条件下,该值会变大.计算方法:Nms<=0xffffff*8/SYSCLK.

    在包括了这个头函数之后可以得到很准确的延时,也不会产生中断,其他中断可以打断delay_us,delay_ms的执行.

#ifndef __DELAY_H
#define __DELAY_H      
//使用SysTick的普通计数模式对延迟进行管理
//包括delay_us,delay_ms 
//正点原子@SCUT
//2008/12/13 
static u8  fac_us=0;//us延时倍乘数
static u16 fac_ms=0;//ms延时倍乘数
//初始化延迟函数
void delay_init(u8 SYSCLK)
{
 SysTick->CTRL&=0xfffffffb;//选择内部时钟 HCLK/8
 fac_us=SYSCLK/8;     
 fac_ms=(u16)fac_us*1000;
}           
//延时Nms
//注意Nms的范围
//Nms<=0xffffff*8/SYSCLK
//对72M条件下,Nms<=1864
void delay_ms(u16 nms)
{   
 SysTick->LOAD=(u32)nms*fac_ms; //时间加载 
 SysTick->CTRL|=0x01;               //开始倒数   
 while(!(SysTick->CTRL&(1<<16)));   //等待时间到达
 SysTick->CTRL&=0XFFFFFFFE;         //关闭计数器
 SysTick->VAL=0X00000000;           //清空计数器    
}  
//延时us          
void delay_us(u32 Nus)

 SysTick->LOAD=Nus*fac_us;       //时间加载     
 SysTick->CTRL|=0x01;            //开始倒数   
 while(!(SysTick->CTRL&(1<<16)));//等待时间到达
 SysTick->CTRL=0X00000000;       //关闭计数器
 SysTick->VAL=0X00000000;        //清空计数器    

#endif

系统分类: ARM  |  用户分类: STM32学习  |  标签: STM32 SysTick 精确延时 非中断 不用ST库函数  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(1119) | 回复(0)

发表于 2008/12/14 19:18:49

1

关于投票

STM32窗口看门狗使用?(WWDG)

    上午搞定RTC之后,开始弄IWDG和WWDG,IWDG比较容易,配置也很简单,参考ST的代码就能很快搞定.但是WWDG就不行了,搞了很久都不行,按ST的库做,在keil上仿真也不行,主要原因就是WWDG->CR寄存器中的计数值不会减少!

      其他配置也都正确了,WWDG->CR就是不减少,我不知道是不是PCLK1的时钟没有,但是从keil的仿真可以看到PCLK1的时钟是36M,没道理没有,很是郁闷,不知道哪位朋友用过STM32的WWDG没有?请指教!

多谢先.

我用的是STM32F103RBT6.

主函数:

#include "stm32f10x_lib.h"
#include "sys.h"  
#include "led.h"
#include "delay.h" 
#include "wwdg.h"          
int main(void)//GPIO
{  
 //u32 temp;     
 Stm32_Clock_Init();//系统时钟设置      
    led_init();
 //DBGMCU->CR=0X00000000;
 delay_init(72);//72M系统时钟
    //delay_ms(300);
 wwdg_init();   //配置并使能IWDG   
 //temp=DBGMCU->CR;
 while (1)
    {       
     LED0_SET(0);
  //WWDG->CR&=~(1<<6);
  delay_us(500000);//在这里系统重启          
    }     
}
 

wwdg.h代码:

#ifndef __WWDG_H
#define __WWDG_H
//看门狗定时器中断配置
void NVIC_WWDGConfiguration(void)
{
 NVIC_InitTypeDef NVIC_InitStructure; 
 #ifdef  VECT_TAB_RAM           
  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
 #else  /* VECT_TAB_FLASH  */        
  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
 #endif     
 NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQChannel;
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
 NVIC_Init(&NVIC_InitStructure);
}
void wwdg_init(void)

 NVIC_WWDGConfiguration();
        
 RCC->APB1ENR|=1<<11; //窗口看门狗时钟使能.       
   WWDG->CFR|=1<<8;     //CLKww=PCLK1/4096/8=244Hz
   WWDG->CFR|=1<<7;  

 WWDG->CFR&=0X380; 
 WWDG->CFR|=65;   //窗口值设置为65
 
 WWDG->CR=0X7F;   //计数值设定为0X7F
 WWDG->CR|=1<<7;      //开启看门狗   
 
 WWDG->SR&=0XFFFFFFFE;//清除EWIF位
 
 WWDG->CFR|=1<<9;     //提前唤醒中断
}
//串口看门狗中断
void WWDG_IRQHandler(void)
{        
   WWDG_SetCounter(0x7F);   
   WWDG_ClearFlag(); 
}
#endif  

sys.h中的代码:

#ifndef __SYS_H
#define __SYS_H    
#include "stm32f10x_lib.h"
//系统时钟初始化
//使用外部8M晶振,PLL到72M频率     
//正点原子@SCUT
//2008/12/04
#define uint unsigned int
#define uchar unsigned char
/*
#define CLOCK 72/8 //时钟=72M

//us延时函数
void delay_us(unsigned int us)
{
 u8 n;     
 while(us--)for(n=0;n<CLOCK;n++);  
}
//ms延时函数
void delay_ms(unsigned int ms)
{
 while(ms--)delay_us(1000); 
} */

//把所有时钟寄存器复位
void RCC_RESETInit(void)
{
 RCC->APB2RSTR = 0XFFFFFFFF;//外设复位   
 RCC->APB1RSTR = 0XFFFFFFFF;            
 RCC->APB2RSTR = 0X00000000;//复位恢复   
 RCC->APB1RSTR = 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;     //关闭所有中断
}

//外部8M,则得到72M的系统时钟 
void Stm32_Clock_Init(void)
{
 unsigned char temp="0";
 u8 timeout="0";
 RCC_RESETInit();
 RCC->CR|=0x00010000;  //外部高速时钟使能HSEON

 timeout=0;
 while(!(RCC->CR>>17)&&timeout<200)timeout++;//等待外部时钟就绪 

 //0-24M 等待0;24-48M 等待1;48-72M等待2;(非常重要!)   
 FLASH->ACR|=0x32;//FLASH 2个延时周期

 RCC->CFGR|=0X001D2400;//APB1/2=DIV2;AHB=DIV1;PLL=9*CLK;HSE作为PLL时钟源
 RCC->CR|=0x01000000;  //PLLON

 timeout=0;
 while(!(RCC->CR>>25)&&timeout<200)timeout++;//等待PLL锁定

 RCC->CFGR|=0x00000002;//PLL作为系统时钟
 while(temp!=0x02&&timeout<200)     //等待PLL作为系统时钟设置成功
 {  
  temp=RCC->CFGR>>2;
  timeout++;
  temp&=0x03;
 } 
}
#endif

delay.h中的代码:

#ifndef __DELAY_H
#define __DELAY_H      
//使用SysTick的普通计数模式对延迟进行管理
//包括delay_us,delay_ms 
//正点原子@SCUT
//2008/12/13 
static u8  fac_us=0;//us延时倍乘数
static u16 fac_ms=0;//ms延时倍乘数
//初始化延迟函数
void delay_init(u8 SYSCLK)
{
 SysTick->CTRL&=0xfffffffb;//选择内部时钟 HCLK/8
 fac_us=SYSCLK/8;     
 fac_ms=(u16)fac_us*1000;
}           
//延时Nms
//注意Nms的范围
//Nms<=0xffffff*8/SYSCLK
//对72M条件下,Nms<=1864
void delay_ms(u16 nms)
{   
 SysTick->LOAD=(u32)nms*fac_ms; //时间加载 
 SysTick->CTRL|=0x01;               //开始倒数   
 while(!(SysTick->CTRL&(1<<16)));   //等待时间到达
 SysTick->CTRL&=0XFFFFFFFE;         //关闭计数器
 SysTick->VAL=0X00000000;           //清空计数器    
}  
//延时us          
void delay_us(u32 Nus)

 SysTick->LOAD=Nus*fac_us;       //时间加载     
 SysTick->CTRL|=0x01;            //开始倒数   
 while(!(SysTick->CTRL&(1<<16)));//等待时间到达
 SysTick->CTRL=0X00000000;       //关闭计数器
 SysTick->VAL=0X00000000;        //清空计数器    

#endif

led.h中没什么其他配置,应该不影响WWDG的,希望高手指教阿!

 

系统分类: ARM  |  用户分类: STM32学习  |  标签: STM32 WWDG 窗口看门狗  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(846) | 回复(0)

发表于 2008/12/14 19:08:04

4

关于投票

STM32实时时钟(RTC)

     昨天下午调试STM32的RTC功能,参照ST提供的源码,还比较好做,后来想给价格串口修改时间.发现了串口的问题.串口通讯是前几天就写好的,发送接收都没问题.不过今天就发现了不能连续接收字符!只能单个接收,郁闷了好久,从下午5点,搞到晚上两点,找遍了所有资料,最终还是没有搞出来.没办法,不搞了.明天再说.

....

今天早上起来十点多了,继续搞我那个串口的问题,发现每次发送的字符串,只有第一个接收正确,但是串口接收中断却运行了很多次,明显大于我发送的字符串个数.但是如果只发一个数据的时候,它的接收却正常.检查了好几次代码了,都没发现问题.设置也正常. KEIL仿真也很正常.不过keil仿真不能一次接收好几个字符(或者我不知道怎么发).

      按道理没可能串口不能连续接收的,因为我的代码是串口下载的,和我用来通讯的是同一个串口,应该硬件上没有问题的.所以开始怀疑是寄存器设置的问题,于是在代码里增加了好几个与串口相关的寄存器值显示.结果发现USART1->CR1的值和仿真的值不完全一致.一查寄存器的位,才发现寄存器确实有问题,串口USART1->CR1的值和复位的值不一致(复位0X00000000),于是检查串口1的复位代码,一查才发现根本就没有设置复位!于是把代码改了,加入复位代码.终于在改过之后接收正常了!可以连续接收了.

      这个程序耗了我很多时间,所以希望和我一样正在开始学STM32的朋友们,要注意系统复位的检查.寄存器的设置.能少走弯路!

我的串口头函数代码:

#ifndef __USART_H
#define __USART_H
#include "stdio.h"
//注意要包含库:STM32F10xR.LIB,提供USART_SendData()和USART_GetFlagStatus()这两个函数
//正点原子@SCUT
//2008/12/08  
#ifdef __GNUC__        
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
//重定义C语言库函数printf到串口1
PUTCHAR_PROTOTYPE
{          
 USART_SendData(USART1,(u8)ch);//写一个字符到串口1
   while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//循环发送,直到发送完毕  
   return ch;
}   
//中断优先级管理/开启   
void NVIC_Configuration(void)
{
 NVIC_InitTypeDef NVIC_InitStructure; 
 #ifdef  VECT_TAB_RAM             
  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
 #else          
  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);  
 #endif                  
 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);   
 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 NVIC_Init(&NVIC_InitStructure);          
}
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 time_set[7]; //时间设置寄存器 
u8 rebuffer[14];//接收缓冲 
u8 recount="0";   //接收完全    
void USART1_IRQHandler(void)
{
 u8 res;    
 if(USART1->SR&(1<<5))//接收到数据
 { 
  res=USART1->DR;        
  if(recount<14&&res>47&&res<58)//仅仅接收数据
  {
   rebuffer[recount]=res-'0';//得到ASCII
   recount++;
  }                 
 } 
}           
//初始化IO 串口1
void uart_init()
{    
 RCC->APB2RSTR|=1<<14;   //复位串口1
 RCC->APB2RSTR&=~(1<<14);//停止复位
 //先使能时钟(切记)
    RCC->APB2ENR|=1<<9;   //TX
 RCC->APB2ENR|=1<<10;  //RX  
 GPIOA->CRH=0X444444B4;//IO状态设置
 RCC->APB2ENR|=1<<2;   //使能PORTA口时钟 
 RCC->APB2ENR|=1<<14;  //使能串口时钟
 //波特率设置
  USART1->BRR=0X1D4C;    //9600波特率(72M时钟) 
 USART1->CR1|=0X200C;   //1位停止,无校验位.
 //使能接收中断
 USART1->CR1|=1<<8;    //PE中断使能
 USART1->CR1|=1<<5;    //接收缓冲区非空中断使能 
 NVIC_Configuration(); //中断开启 
}
#endif

全图

点击看大图

全图点击看大图

屏幕1

点击看大图

屏幕2

 附上我的代码(RVMDK):http://space.ednchina.com/upload/2008/12/14/8a53b564-d490-49dc-95fb-d184abae8d9b.rar

系统分类: ARM  |  用户分类: STM32学习  |  标签: STM32 RTC 实时时钟 串口通讯 USART  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(1330) | 回复(3)

发表于 2008/12/9 19:17:01

3

关于投票

自制的STM32开发板(STM32F103RBT6)

http://space.ednchina.com/upload/2008/12/9/c2294a52-04d9-4e28-8f40-13ac484014b5.rar" target=_blank>实验室快关门了,于是赶着这时间把一直想搞的STM32开发板给做了,顺便把那个2.4寸TFT的转接板也做了,加了个触摸屏.这里上传我的资料.希望对网友有帮助.
    我一贯是以实用至上,这次也不例外,开发板分为核心板和主板,主板提供核心板的必要外围设备,同时在没有核心板的时候,主板就成了一个通用的了,为其他核心板(像我做的CPLD/ADUC7027之类的)提供外设了.主板载有功能:
1,5V,3.3V电源输出(由USB供电或者外部电源都可)
2,USB串口一个(CH341),通用串口2个(MAX232)
3.USB接口一个,支持U盘或者与电脑连接
4,按键三个
5,LED4个
6,SD卡接口一个
7,CAN接口一个
8,PWM音频输出口一个,可作DAC或者音频试验
9,PS2接口一个.
10,红外接口一个
11,ADC参考电压一个
12,备用电源一个.
13,液晶接口两个(TFTLCD和13164液晶接口)
    以上这些接口在拔出核心板之后,对外全部开放,可以用来做各种试验了.可以狠方便搭载各种试验平台(本人多年做硬件的经验,呵呵).以后各位要学其他的,可以只做核心板,其他常用的的接口在这个主板上全部载有.可以省掉很多银子(我这套东东:开发板+TFTLCD+触摸屏(带ADS7846)总共价格就在120块左右).当然核心板也是可以独立工作的,用串口下载,只要接上电源和串口,核心板就能跑了,你也可以放到其他平台上使用,这样.

    通过两天的学习,调试.可以跑程序了.STM32也是在板子做好之后才开始接触的,这两天看了些,就写了几个简单的程序,对STM32还只会用IO口,其他功能还得以后慢慢学了.代码都是自己敲的,不喜欢用ST的库函数,感觉别扭(用惯了CVAVR).个人认为用ST的库函数不爽,理由如下:
1,不了解硬件了(和自己的定位脱钩)
2,受制于人(最不爽)
3,不习惯被人牵着鼻子走(个人性格)
4,自己写,才能真正了解.如果只要写代码,我大可以学C++就够了,没必要搞这么多其他东东..

    在想如果可以做个想CVAVR那样的代码自动生成器,多好阿.有时间弄个玩玩,现在先了解这个芯片的内部资源.待我熟悉之后估计会写个这样的代码生成器来,方便各位使用,呵呵.

核心板原理图:点击看大图

核心板

点击看大图

LCD照片

点击看大图

LCD显示效果

点击看大图

主板和核心板

点击看大图

侧面1

点击看大图

侧面2

点击看大图

侧面3

点击看大图

全副武装.

点击看大图

测试1

点击看大图

测试2

点击看大图

主板和CPU分离

点击看大图

主板

点击看大图

背面

 

系统分类: ARM  |  用户分类: STM32学习  |  标签: STM32 TFT LCD STM32F103RBT6 液晶  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(3037) | 回复(2)

Total , Page /