分享

Lcd1602 for STM32

 戴维图书馆 2013-11-12
  1. Keil的编译优化问题:http://www.360doc.com/content/11/0126/14/2379862_89135875.shtml  
  1. /***********Lcd1602 for STM32 ********************/   
  2. /* 
  3.  *BUG:打开测忙函数不能显示,由于STM32 比 LCD1602 相应速度较快, 
  4.  *ns级的单片机需要等待us级的LCD,(可以通过延时来实现) 
  5.  *否则会造成数据读写溢出 
  6.  */  
  7. /* 
  8.  * 1602 的 供电电压为5V,显示比较清晰,如跟STM32一样用3.3V供电则比较模糊 
  9.  */  
  10. #include "stm32f10x_lib.h"   
  11.   
  12. /********************************硬件接口定义*********************************/  
  13. #define RS  GPIO_Pin_1 //P2^6-1; 4-3                
  14. #define RW  GPIO_Pin_2 //P2^5-2; 5-2   
  15. #define EN  GPIO_Pin_0 //P2^7-0; 6-1   
  16.   
  17. /********************************宏定义*********************************/  
  18. #define    Lcd_RS(x)  x ? GPIO_SetBits(GPIOB, RS): GPIO_ResetBits(GPIOB, RS)   
  19. #define    Lcd_RW(x)  x ? GPIO_SetBits(GPIOB, RW): GPIO_ResetBits(GPIOB, RW)   
  20. #define    Lcd_EN(x)  x ? GPIO_SetBits(GPIOB, EN): GPIO_ResetBits(GPIOB, EN)   
  21.   
  22. /******************************** 变量定义 --------------------------------------*/  
  23. GPIO_InitTypeDef GPIO_InitStructure;     //GPIO   
  24. ErrorStatus HSEStartUpStatus;  
  25.   
  26.       
  27. typedef unsigned char BYTE;  
  28. typedef unsigned char BOOL;   
  29.   
  30. BYTE dis1[] = {"  WELCOME   TO  "};  
  31. BYTE dis2[] = {" STM32  Lcd1602 "};  
  32.   
  33. /*********************************声明函数 ---------------------------------------*/  
  34. void RCC_Configuration(void);  
  35. void NVIC_Configuration(void);  
  36.   
  37. /*****************************延时函数*********************************************/  
  38. void delay_nus(u32 n)//微秒级延时,通常情况此函数可以不用更改   
  39. {  
  40.     u8 i;  
  41.     while(n--)  
  42.     {  
  43.         i=7;  
  44.         while(i--);  
  45.   }  
  46. }  
  47.   
  48. void delay_nms(u32 n) //毫秒级延时,通常情况此函数可以不用更改   
  49. {  
  50.     while(n--)  
  51.     {  
  52.         delay_nus(1100);  
  53.     }  
  54. }  
  55.   
  56.   
  57. /******************************测忙************************************************/    
  58. BOOL Lcd_Busy()  
  59. {                         // 测试Lcd忙碌状态   
  60.     vu8 temp = 0x00ff;  
  61.     GPIO_Write(GPIOB, 0xffff);  
  62.     Lcd_RS(0);    
  63.     delay_nus(10);  
  64.     Lcd_RW(1);   
  65.     delay_nus(10);   
  66.     Lcd_EN(1);  
  67.     delay_nus(10);  
  68.   
  69.     while((GPIO_ReadInputData(GPIOB) & 0x8000)>>8)  
  70.     {  
  71.         delay_nus(20);  
  72.     }  
  73.   
  74.     delay_nus(10);  
  75.     Lcd_EN(0);  
  76.     delay_nus(10);  
  77.   
  78.     return (BOOL)0;  
  79. }  
  80. /******************************写命令*********************************************/      
  81. Lcd_Wcmd(vu16 cmd)  
  82. {                            
  83.     //while(Lcd_Busy());   
  84.     Lcd_EN(0);  
  85.     delay_nus(1);  
  86.     Lcd_RS(0); // 写入指令数据到Lcd   
  87.     delay_nus(1);  
  88.     Lcd_RW(0);   
  89.     delay_nus(1);  
  90.   
  91.     GPIOB->BSRR = cmd<<8 & 0xff00;  //将数据送到P0口    
  92.     GPIOB->BRR = ((~cmd)<<8) & 0xff00;  
  93.     delay_nus(500);  
  94.   
  95.     Lcd_EN(1);  
  96.     delay_nms(1);  
  97.     Lcd_EN(0);  
  98.     delay_nus(100);  
  99. }  
  100. /******************************设置位置*********************************************/         
  101. Lcd_Pos(BYTE strPos)  
  102. {                          //设定显示位置   
  103.     Lcd_Wcmd(strPos | 0x80);  
  104. }  
  105.   
  106. /******************************写数据***********************************************/    
  107. Lcd_Wdat(vu16 nDat)   
  108. {                            
  109.     //while(Lcd_Busy());   
  110.     Lcd_EN(0);   
  111.     delay_nus(1);  
  112.     Lcd_RS(1); //写入字符显示数据到Lcd   
  113.     delay_nus(1);  
  114.     Lcd_RW(0);   
  115.     delay_nus(1);  
  116.   
  117.     GPIOB->BSRR = nDat<<8 & 0xff00;    //P0 = dat   
  118.     GPIOB->BRR = ((~nDat)<<8) & 0xff00;  
  119.     delay_nus(500);  
  120.   
  121.     Lcd_EN(1);  
  122.     delay_nms(1);   //延时300us以上才可以   
  123.     Lcd_EN(0);  
  124.     delay_nus(100);  
  125. }  
  126.   
  127. /******************************写字符串***********************************************/  
  128. Lcd_String(BYTE *strWrite)  
  129. {  
  130.     BYTE i;  
  131.     i = 0;  
  132.     while(strWrite[i] != '\0')  
  133.     {                            
  134.         Lcd_Wdat(strWrite[i]);  
  135.         i++;  
  136.     }  
  137. }  
  138. Lcd_Init()  
  139. {                            //Lcd初始化设定   
  140.     delay_nms(15);  
  141.     Lcd_Wcmd(0x38);          //16*2显示,5*7点阵,8位数据   
  142.     delay_nms(5);  
  143.     Lcd_Wcmd(0x08);  
  144.     delay_nms(5);  
  145.     Lcd_Wcmd(0x0c);          //显示开,关光标   
  146.     delay_nms(5);  
  147.     //Lcd_Wcmd(0x06);        //移动光标   
  148.     delay_nms(5);  
  149.     Lcd_Wcmd(0x01);          //清除Lcd的显示内容   
  150.     delay_nms(5);  
  151. }  
  152. Test_GPIOA(vu16 *GPIOATemp)  
  153. {  
  154.     GPIO_Write(GPIOA, *GPIOATemp);       
  155.     *GPIOATemp = *GPIOATemp << 1;  
  156.     if(*GPIOATemp > 256)  
  157.     {  
  158.         *GPIOATemp = 0x0001;  
  159.     }  
  160.     while(0);  
  161.     delay_nms(1000);  
  162.     while(0);   
  163. }  
  164.   
  165.       
  166. main()  
  167. {  
  168.     vu16 GPIOAInitStatus = 0x0001;  
  169.   
  170. #ifdef DEBUG   
  171. debug();  //在线调试使用   
  172. #endif   
  173.       
  174.     RCC_Configuration();      //系统时钟配置函数    
  175.       
  176.     NVIC_Configuration();     //NVIC配置函数    
  177.     //启动GPIO模块时钟   
  178.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB1Periph_TIM2 | RCC_APB2Periph_AFIO, ENABLE);  
  179.     //把调试设置普通IO口   
  180.     //GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);     
  181.                               
  182.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;          //所有GPIO为同一类型端口   
  183.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     //推挽输出   
  184.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    //输出的最大频率为50HZ   
  185.     GPIO_Init(GPIOA, &GPIO_InitStructure);   //初始化GPIOA端口   
  186.     GPIO_Init(GPIOB, &GPIO_InitStructure);   //初始化GPIOB端口   
  187.   
  188.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 |GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15   
  189.                                   | GPIO_Pin_2 | GPIO_Pin_1 | GPIO_Pin_0; //所有GPIO为同一类型端口   
  190.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     //推挽输出   
  191.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    //输出的最大频率为50HZ   
  192.     GPIO_Init(GPIOB, &GPIO_InitStructure);               //初始化GPIOB端口   
  193.   
  194.     GPIO_Write(GPIOA,0x0000);  //将GPIOA 16个端口全部置为低电平   
  195.     GPIO_Write(GPIOB,0xffff);  //将GPIOB 16个端口全部置为高电平   
  196.   
  197.     Lcd_Init();               // 初始化Lcd   
  198.   
  199.     Lcd_Pos(0);                //设置显示位置为第一行的第1个字符   
  200.     Lcd_String(dis1);  
  201.     Lcd_Pos(0x40);             //设置显示位置为第二行的第1个字符   
  202.     Lcd_String(dis2);     
  203.   
  204.     while(1)                
  205.     {                 
  206.         Test_GPIOA(&GPIOAInitStatus);  
  207.     }  
  208. }  
  209.   
  210. /******************************************************************************* 
  211. *                           配置RCC 
  212. *******************************************************************************/  
  213. void RCC_Configuration(void)  
  214. {     
  215.  //复位RCC外部设备寄存器到默认值   
  216.   RCC_DeInit();  
  217.   
  218.   //打开外部高速晶振   
  219.   RCC_HSEConfig(RCC_HSE_ON);  
  220.   
  221.   //等待外部高速时钟准备好   
  222.   HSEStartUpStatus = RCC_WaitForHSEStartUp();  
  223.   
  224.   if(HSEStartUpStatus == SUCCESS)   //外部高速时钟已经准别好   
  225.   {                                   
  226.     //开启FLASH的预取功能   
  227.     FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);  
  228.   
  229.     //FLASH延迟2个周期   
  230.     FLASH_SetLatency(FLASH_Latency_2);  
  231.       
  232.     //配置AHB(HCLK)时钟=SYSCLK   
  233.     RCC_HCLKConfig(RCC_SYSCLK_Div1);    
  234.     
  235.     //配置APB2(PCLK2)钟=AHB时钟   
  236.     RCC_PCLK2Config(RCC_HCLK_Div1);   
  237.   
  238.     //配置APB1(PCLK1)钟=AHB 1/2时钟   
  239.     RCC_PCLK1Config(RCC_HCLK_Div2);  
  240.   
  241.     //配置PLL时钟 == 外部高速晶体时钟*9  PLLCLK = 8MHz * 9 = 72 MHz    
  242.     RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);  
  243.   
  244.     //使能PLL时钟   
  245.     RCC_PLLCmd(ENABLE);  
  246.   
  247.     //等待PLL时钟就绪   
  248.     while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)  
  249.     {  
  250.     }  
  251.   
  252.     //配置系统时钟 = PLL时钟   
  253.     RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);  
  254.   
  255.     //检查PLL时钟是否作为系统时钟   
  256.     while(RCC_GetSYSCLKSource() != 0x08)  
  257.     {  
  258.     }  
  259.   }  
  260. }  
  261.   
  262.   
  263. /******************************************************************************* 
  264. *                             NVIC配置函数 
  265. *******************************************************************************/  
  266. void NVIC_Configuration(void)  
  267. {  
  268.  NVIC_InitTypeDef NVIC_InitStructure;  
  269. #ifdef  VECT_TAB_RAM     
  270.   /* Set the Vector Table base location at 0x20000000 */   
  271.   NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);   
  272. #else  /* VECT_TAB_FLASH  */   
  273.   /* Set the Vector Table base location at 0x08000000 */   
  274.   NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);     
  275. #endif   
  276.   
  277.     
  278.   /* 开启定时器2 */  
  279.   NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;  
  280.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
  281.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  
  282.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
  283.   NVIC_Init(&NVIC_InitStructure);  
  284. }  
  285.   
  286.   
  287.   
  288. #ifdef  DEBUG   
  289. /******************************************************************************* 
  290. * Function Name  : assert_failed 
  291. * Description    : Reports the name of the source file and the source line number 
  292. *                  where the assert_param error has occurred. 
  293. * Input          : - file: pointer to the source file name 
  294. *                  - line: assert_param error line source number 
  295. * Output         : None 
  296. * Return         : None 
  297. *******************************************************************************/  
  298. void assert_failed(u8* file, u32 line)  
  299. {   
  300.   /* User can add his own implementation to report the file name and line number, 
  301.      ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */  
  302.   
  303.   /* InfInite loop */  
  304.   while (1)  
  305.   {  
  306.   }  
  307. }  
  308. #endif  

注意:

(1)STM32驱动1602没法显示的原因之一:GPIO口直接连接1602,需要用10k的电阻上拉。

(2)写指令和写数据,差别仅仅在于RS的电平不一样而已,即引脚RS是数据和命令选择端,S应该是Select的缩写,输入参数的DATA,要么是命令,要么是数据。

(3)RW是R/W的缩写,斜杆也是选择的意思,读即R(高电平有效),写即W(低电平有效)

(4)要将E引脚置为低电平,为下一次E的高脉冲做准备,这称为释放时钟线。

(5)时序图读法:从上到下,从左到右,高电平在上,低电平在下,高阻态在中间。双线表示可能高也可能低,视数据而定。交叉线表示状态的高低变化点,可以是高变低,也可以是低变高,也可以不变。竖线是生命线,代表时序图的对象在一段时期内的存在,时序图中每个对象和底部中心都有一条垂直段的虚线,这就是对象的生命线,对象的消息存在于两条生命线之间。

(6)读写时序图之前一般需要初始化,而初始化有可能模式选择,引脚电平初始化等。

相关链接:http://hi.baidu.com/houyulin016/item/114631c0d9d3a72647d5c05f


更多 0

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多