原创 STM32的SPI应用之LCD

2008-4-30 23:34 6499 4 7 分类: MCU/ 嵌入式

STM32SPI应用之LCD


源代码:点击下载


介绍文档:点击下载<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


       开始本来先玩串口,虽然程序已经跑通,但是由于网上类似文章很多,就先来个SPI玩玩,与上次GPIO一样,技术含量仍然不高,仅是业余学习玩玩。


1、  首先来开硬件电路,个人觉得是编写程序的第2步;第1步当然是先看STM32的手册了,SPI的详细介绍见STM32的中文使用手册。


 


<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />点击看大图


这个电路的正确性是以我把它点亮为依据的,不是我设计的,我也不会,但是我驱动它关心的是那几个信号引脚怎么接的。这里采用的是SPI口,加上几根控制线。关于SPI口的介绍不大清楚的朋友可以查下相关资料,一般具有SPI接口的处理器的手册都有比较详细的介绍。


结合STM32的手册对引脚的描述:


点击看大图



可以看出,SPI14根引脚MISOMOSISCKCLK)、CSNCS)分别对应的引脚为GPIO的:PA6PA7PA5PA4


所以LCD的控制线与处理器的GPIO具体对应如下:


LCD_RST--------------PC7


LCD_RS------------------PC8


LCD_CLK-----------------------PA5


LCD_SDO-----------------------PA7


LCD_CS----------------------PA8


LCD_PWR----------------PC1


       其实也就这六根信号线就能驱动LCD了。


       2、这里必须关心的是SPI口对应的4根线,这里只用到了两根MOSIPA7)、CLKPA5),片选CSN用的是通用IOPA8代替,至于MISO这里可以不用使用。


       所以在初始化SPI口是有如下程序:


void SetupSPI(void)


{


  SPI_InitTypeDef  SPI_InitStructure;


  GPIO_InitTypeDef GPIO_InitStructure;


  /*允许 SPI1 GPIOA时钟,这两个外设都是挂在APB2总线上的 */


  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_GPIOA, ENABLE);


 


  /*配置 SPI1 引脚,由于这里只用到了 SCK, MOSI ,所以只对PA5PA7进行了初始化*/


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;


  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//关于这个参数的描述可以见GPIOH文件


  GPIO_Init(GPIOA, &GPIO_InitStructure);


 


  /* 配置PA.4作为推挽输出,因为这里用来作为SPI口的片选,既选中LCD操作 */


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;


  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;


  GPIO_Init(GPIOA, &GPIO_InitStructure);


 


  /* 初始化片选为高,不选种LCD */


  GPIO_ResetBits(GPIOA, GPIO_Pin_8);//PA8;


 


  /* SPI1 配置,关于这个怎么配置见STM32的手册,为什么这样配置见下 */


  SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;


  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;


  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;


  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;


  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;


  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;


  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;


  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;


  SPI_Init(SPI1, &SPI_InitStructure);


 


  SPI_Cmd(SPI1, ENABLE);  


}


关于SPI的配置,这里还要多说点。因为SPI的时序很重要,或者说只要是串口,对时序都有一些特定的要求。对于STM32SPI口来说,时序是可以配置。


先来看看STM32 SPI口时序图:


点击看大图



       可以看出,SPI口的时序主要控制在两个位:CPHACPOL,这个不用我多罗嗦,大家都知道两个位组合一共有4种组合,也就是说SPI4种时序,那么这里选择哪一种呢?这就要取决与所用LCD的驱动IC了。这里采用的驱动IC,下面来看看LCD驱动ICSPI口的时序:


点击看大图


      


       我想看到这里,稍微有点眼神的人都能看出来这个时序与STM32 的哪个对应了。这里应该设置STM32CPHA=1CPOL=1。它的意义为:SPI空闲保持高电平,在时钟的第2个边沿采样。其他具体信息可以去看使用手册,里面有相当详细的介绍。


       那么在固件函数库里需要设置对应的初始化参数为:


       SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;


       SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;


       从英文意思上也能看出两个参数的意义,我就是这么看出来的,使用手册太长,而且是电子版的,看起来不太适应(本人喜欢看书,所以现在在等待STM32的书出版,该书应该很快会出来了,应该是英蓓特组织出的,MDK那个书已经出来了,周末去书店逛了下,看见还可以,不过没有买,原因有2:第1我现在做市场没有太多的时间去研究MDK,第2本人经济拮据------留着钱过5.1)。


       SPI口配置还有几个参数,其实从英文意义上都不难理解(申明本人英文很菜,我能看懂的我相信大家都绝对没有问题)。


       SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;


配置SPI为只输出,这个SPI口的输入输出方向好象有4种,这也是从H文件看到的:


#define SPI_Direction_2Lines_FullDuplex    ((u16)0x0000)


#define SPI_Direction_2Lines_RxOnly        ((u16)0x0400)


#define SPI_Direction_1Line_Rx             ((u16)0x8000)


#define SPI_Direction_1Line_Tx             ((u16)0xC000)


       分别代表的意义从字面上也好理解,要是对应使用手册来看,我相信效果更好。


     SPI_InitStructure.SPI_Mode = SPI_Mode_Master;


       SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;


       这个是配置为主模式和8位数据-----我肯定,呵呵!STM32SPI口还可以为从模式、16位数据方式。


       SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;


       SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;


       SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;


       这几个位就更加容易理解了,SPI_NSS_Soft;软件设置片选,这个介绍起来有点罗嗦,可以看使用手册(偷个小懒),SPI_BaudRatePrescaler_4这个是拨特率设置,可以设置为如下参数:


         #define SPI_BaudRatePrescaler_2            ((u16)0x0000)


#define SPI_BaudRatePrescaler_4            ((u16)0x0008)


#define SPI_BaudRatePrescaler_8            ((u16)0x0010)


#define SPI_BaudRatePrescaler_16           ((u16)0x0018)


#define SPI_BaudRatePrescaler_32           ((u16)0x0020)


#define SPI_BaudRatePrescaler_64           ((u16)0x0028)


#define SPI_BaudRatePrescaler_128          ((u16)0x0030)


#define SPI_BaudRatePrescaler_256          ((u16)0x0038)


       这里设置为多少其实都应该可以的。


       SPI_FirstBit_MSB这个的意思是第一个位为最高位。因为是串行传输,所以移位肯定有先后的。从时序图上也能看出来高位先行。


       3SPI配置完后就要写LCD驱动了,这个驱动也是拿现成的修改的,凭本人的技术水准很难把LCD手册看明白,也很难自己一个字母一个字母把驱动写出来。既然有高手写好了,就不妨拿来借鉴!这个也是省事的办法,要是哪位有兴趣研究驱动,可以自己尝试写下,写好了也象我这样写过简单的过程再公开,那就功德无量了!不过就我了解,现在做芯片的厂商都会把驱动写好的,就象ST一样,把芯片的固件库写的很完善,方便了我这样的技术半吊子水准的人。


       首先定义下LCD的控制引脚,这样操作起来方便:


//LCD_RST


#define LCD_RST_SET                         GPIO_SetBits(GPIOC, GPIO_Pin_7)//PC7


#define LCD_RST_RESET                    GPIO_ResetBits(GPIOC, GPIO_Pin_7)//PC7


 


//LCD_RS


#define LCD_RS_SET                            GPIO_SetBits(GPIOC, GPIO_Pin_8)//PC8


#define LCD_RS_RESET                       GPIO_ResetBits(GPIOC, GPIO_Pin_8)//PC8


 


//LCD_CS 


#define LCD_CS_SET                            GPIO_SetBits(GPIOA, GPIO_Pin_8)//PA8


#define LCD_CS_RESET                      GPIO_ResetBits(GPIOA, GPIO_Pin_8)//PA8


 


// LCD_PWR


#define LCD_PWR_SET                        GPIO_SetBits(GPIOC, GPIO_Pin_1)//PC1


#define LCD_PWR_RESET                   GPIO_ResetBits(GPIOC, GPIO_Pin_1)//PC1


       上面定义完全是为了程序操作方便。也是我见到的比较好的编程习惯。


       由于LCD驱动比较多,为了不浪费篇幅,这里只写两个比较重要的函数:


/*******************************************************************************


//函数名void Lcdwritecom(int8u com)


//功能lcd写指令


//输入com指令


//输出


********************************************************************************/


void Lcdwritecom(INT8U com)


{


         LCD_CS_RESET;                 //片选拉低,选中LCD


         LCD_RS_RESET;                 //设置为写命令


 


         SPI_SendData(SPI1, com);//SPI写数据


         while(SPI_GetFlagStatus(SPI1, SPI_FLAG_BSY) != RESET);//等待发送完成


 


         LCD_CS_SET;                      //片选拉高,释放LCD


}


/*******************************************************************************


//函数名:void Lcdwritedata(int8u dat)


//功能:lcd写数据


//输入:dat数据


//输出:无


********************************************************************************/


void Lcdwritedata(INT8U dat)


{


         LCD_CS_RESET;       //片选拉低,选中LCD


         LCD_RS_SET;             //设置为写数据


 


         SPI_SendData(SPI1, dat); //SPI写数据


         while(SPI_GetFlagStatus(SPI1, SPI_FLAG_BSY) != RESET); //等待发送完成


         LCD_CS_SET;             //片选拉高,释放LCD


}


       差不多到最后了,秀下主函数:


int main (void)


{


         INT8U num_test[]="123456789";


         INT8U char_test[]="abcdef";


         INT8U china_test[]="无线测试";


 


    //SetupClock();


    //LED_Init();


    SetupSPI();


 


    InitLcd();


 


    TurnOnDisp();


    Delay(0xfffff);


 


    ClearScreen();


 


  while(1){


       Rectangle(10,0,120,0);           //画线测试


         Rectangle(10,7,120,7);


         Printn(1,10,255,1,3);             //显示整数测试


         Print6(2,10,num_test,1);        //显示数字测试


         Print8(3,10,char_test,1);        //显示字母测试


         Print(5,10,china_test,1);         //显示汉字测试


  }


}


       注意这里把//SetupClock();函数屏蔽了,在源文件中有该函数,也就是配置系统时钟,不配置采用默认时钟。函数里配置为72MHz。关于RCC的一些应用我还没有时间研究,有时间了在好好看看,专门弄几个例子出来表现下。


       就写到这里,明天5.1还要出去玩,早点休息!


 


 


 


                            <?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />20084302330   


                                   YYYtech于成都


 


 


另外这里采用的是STM32硬件SPI,用软件模拟SPI也是可以实现的,有兴趣的可以试下,反正我试了是成功的。准确的说,我是先测试软件SPI成功才用的硬件SPI


 


 


 


 


 


 


 


 

PARTNER CONTENT

文章评论3条评论)

登录后参与讨论

用户239228 2010-1-31 17:11

支持下,写得不错,不过没后文了好像

用户947559 2009-7-21 17:02

我是STM32菜鸟,看了文章深感佩服,希望有幸得到指点

用户1321576 2008-7-16 16:45

支持
相关推荐阅读
用户132238 2009-05-06 09:30
我又回来了!
好久不在这里更新了,主要是最近烦心的事太多。不过现在我成功的回来了!重新开始新的生活了!我的网站再一次开通,前段时间很多网友说没有链接,这里我表示抱歉!不过以后会长期开通并随时更新,希望与大家一起进步...
用户132238 2009-02-10 22:41
TI-MAC实验包(MSP430+CC2520)
TI-MAC实验包(MSP430+CC2520) 实验内容1、设置通道和传输率在mac_api.h文件中有如下定义:#define MAC_CHAN_11                 11#def...
用户132238 2008-12-12 14:04
SimpleApp例子串口出现乱码的原因?
问题出现可以参看从零开始学习ZSTACK9文章http://www.yyytech.cn/Tech/Read.aspx?id=264提问:“每次发射开始时候会发送乱码出来? <?xml:name...
用户132238 2008-12-11 19:03
从零开始学习Z-Stack之9
从零开始学习ZStack之9 作者:YYYtech  发布时间:2008-08-06 21:33:13    已阅读824次从零开始学习Z-Stack之9接到昨天的继续忽悠,话说:2、SimpleAp...
用户132238 2008-12-11 19:02
从零开始学习Z-Stack之8
从零开始学习ZStack之8 作者:YYYtech  发布时间:2008-08-05    已阅读755次从零开始学习ZStack之8近段时间比较忙,几乎都快荒废了Z-Stack的学习了,把以前学的都...
用户132238 2008-12-11 19:01
从零开始学习Z-Stack之7
从零开始学习ZStack之7 作者:YYYtech  发布时间:2008-07-22 23:27:31    已阅读798次从零开始学习Z-Stack之7--------------Z-Stack指导...
我要评论
3
4
关闭 站长推荐上一条 /3 下一条