加拿大 发表于 2015-7-4 13:58:19

STM32F303+LCD1602程序问题,不只为什么点不亮?

本帖最后由 加拿大 于 2015-7-4 15:47 编辑


/**************************************************************************
**文件名称:LCD1602.hforSTM32
**************************************************************************/
#include"stdint.h"
#ifndefLCD1602_STM32_H
#defineLCD1602_STM32_H

#define LCD_RS_1 GPIO_SetBits(GPIOB, GPIO_Pin_15) //PB.15-(LCD)RS
#define LCD_RS_0 GPIO_ResetBits(GPIOB, GPIO_Pin_15)
#define LCD_RW_1 GPIO_SetBits(GPIOB, GPIO_Pin_14) //PB.14--(LCD)RW
#define LCD_RW_0 GPIO_ResetBits(GPIOB, GPIO_Pin_14)
#define LCD_EN_1 GPIO_SetBits(GPIOB, GPIO_Pin_13) //PB.13--(LCD)E
#define LCD_EN_0 GPIO_ResetBits(GPIOB, GPIO_Pin_13)
#define DATAOUT(x)GPIO_Write(GPIOA, x)         //PA--(LCD)D0~D7

#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif

extern void delay_nms(unsigned long n);
extern void delay_nus(unsigned long n);

uint8_t LCD_busy(void); //读LCD忙碌状态,直到LCD1602不忙为止
void Wait_Leisure(void);//一直等待到LCD1602空闲
void LCD_WriteInitcmd(uchar cmd);//写入LCD初始化时的命令,不可以检测忙状态
void LCD_Writecmd(uchar cmd);//写指令到LCD1602,指令数据占一个字节
void LCD_Writedata(uchar dat);//写一字节数据到LCD1602
void LCD_pos(uchar pos);//设定显示位置 00h~27h,40h~47h
void LCD_Setpos(uchar row,uchar col);//根据习惯设定显示位置
void LCD_DispChar(char ch);//显示一个字符
void LCD_Setpos_DispChar(uchar row,uchar col,char ch);//在指定位置显示一个字符
void LCD_DispString(char str[]);//使LCD1602显示一个字符串,显示位置需提前设定
void LCD_Setpos_DispString(uchar row,uchar col,char str[]);//使LCD1602从指定位置开始显示一个字符串
void LCD_Dispnum(uint32_t num);//显示一个不超过8位的整数,显示位置需提前设置
void LCD_Setpos_Dispnum(uchar row,uchar col,uint32_t num);//在指定位置显示一个不超过8位的整数
void LCD_DispDecimal(uint32_t num,uchar dot);//显示一个有效位不超过8位的浮点数,显示位置需要提前设定
//在指定位置显示一个有效位不超过8位的浮点数
void LCD_Setpos_DispDecimal(uchar row,uchar col,uint32_t num,uchar dot);
//显示日历,显示日期与时间
void LCD_DispDateTime(uint32_t year,uchar month,uchar day,uchar hour,uchar min,uchar sec);
//显示秒表,显示时,分,秒,10毫秒,精确到10ms
void LCD_DispStopWatch(uchar hour,uchar min,uchar sec,uchar tenms);
//显示频率计,动态自动调整频率显示
void LCD_DispFreq(uint32_t freq);
void LCD_ShiftLeft(void);//屏幕整体左移一格,用于滚动显示
void LCD_ShiftRight(void);//屏幕整体右移一格,用于滚动显示
void LCD_Clear(void);//清屏,清除显示
void LCD_Return(void);//使光标还回原点位置
void LCD_Close(void);//关显示
void LCD_Open(void);//开显示
void LCD_FlickerChar(uchar row,uchar col);//使指定位置字符闪烁,不显示光标
void LCD_CloseFlicker(void);//关闭字符闪烁
void LCD_FlickerScreen(void);//屏幕秒闪烁一次
/*********************************************************************
*名    称:LCD_Init()
*功    能:初始化LCD1602
*入口参数:无
*出口参数:无
*常用命令:0x38:16*2显示,5*&点阵显示字符,8位数据;指令执行时间40us
*          0x0C:开显示,关光标   40us
*          0x08:关显示,关光标   40us
*          0x0D:字符闪烁,关光标,接着设定位置,闪烁周期0.4ms左右
*          0x0F:字符闪烁,开光标
*          0x06:写完数据自动右移光标,普通情形,从左向右显示40us
*          0x04:写完数据自动左移光标,可以从右向左显示40us
*          0x01:清除显示内容,即清屏1.64ms
*          0x02:使光标还回起始位置   1.64ms
*          0x18:屏幕上所有字符同时左移一格,适合滚动显示 40us
*          0x1C:屏幕上所有字符同时右移一格,适合滚动显示 40us
*********************************************************************/
void LCD_Init(void);

#endif



/*********************************************************************
* 文件名称:LCD1602.C
* 功能:为51单片机提供LCD1602驱动程序,解决LCD1602与上层软件的隔离问题
*********************************************************************/
#include "stm32f30x.h"
#include "LCD1602.h"
#ifndefLCD1602_STM32_C
#defineLCD1602_STM32_C

/*********************************************************************
*名    称:LCD_busy()
*功    能:读LCD忙碌状态,直到LCD1602不忙为止
*入口参数:无
*出口参数:无符号字节类型,返回0表示LCD已经操作完毕,空闲。
*说    明:一般在写入新命令或数据之前用while(LCD_busy())语句等待LCD就绪
*********************************************************************/
uint8_t LCD_busy(void)
{                        
LCD_RS_0;
delay_nus(1);
LCD_RW_1;
delay_nus(1);
do
{
LCD_EN_0;
delay_nus(200);
LCD_EN_1;
delay_nus(200);
}
while(GPIOD->IDR & 0x80);
LCD_EN_0;
return (uint8_t)0;
}
/*********************************************************************
*功    能:一直等待到LCD1602空闲
*********************************************************************/
void Wait_Leisure(void)
{
LCD_busy();
}
/*********************************************************************
*功    能:写入LCD初始化时的命令,不可以检测忙状态
*********************************************************************/
void LCD_WriteInitcmd(uchar cmd)
{                        
LCD_RS_0;
delay_nus(1);
LCD_RW_0;
delay_nus(1);
DATAOUT(cmd);
LCD_EN_0;
delay_nus(300);
LCD_EN_1;
delay_nus(300);
LCD_EN_0;
delay_nms(2);
}
/*********************************************************************
*名    称:LCD_Writecmd()
*功    能:写指令到LCD1602,指令数据占一个字节
*入口参数:cmd:待写入的指令
*出口参数:无
*********************************************************************/
void LCD_Writecmd(uchar cmd)
{                        
while(LCD_busy());
LCD_RS_0;    //对同一个寄存器的两次写入,中间延时一会
delay_nus(1);
LCD_RW_0;
delay_nus(1);
LCD_EN_0;
delay_nus(300);//产生脉冲
DATAOUT(cmd);
LCD_EN_1;
delay_nus(300);//必要的延时
LCD_EN_0;    //下降沿,LCD1602开始工作
}

/*********************************************************************
*名    称:LCD_Writedata()
*功    能:写一字节数据到LCD1602
*入口参数:dat:无符号字节类型,0~255包括各个ASCII码字符
*出口参数:无
*********************************************************************/
void LCD_Writedata(uchar dat)
{                        
while(LCD_busy());//等待LCD1602空闲
LCD_RS_1;
delay_nus(1);
LCD_RW_0;
delay_nus(1);
DATAOUT(dat);
LCD_EN_1;//先拉高
delay_nus(300); //很重要的延时,经调试,延时300us以上才可以
LCD_EN_0;       //下降沿,开始写入有效数据
}
/*********************************************************************
*名    称:LCD_pos()
*功    能:设定显示位置
*入口参数:pos:显示位置,值的范围如下:
*    0x00----------------0x0f 0x10-------0x27 第一行(一次显示16个字符)
*    0x40----------------0x4f 0x50-------0x67 第二行
*出口参数:无
*********************************************************************/
void LCD_pos(uchar pos)
{                        
LCD_Writecmd(pos | 0x80);
}
/*********************************************************************
*名    称:LCD_Setpos()
*功    能:根据习惯设定显示位置
*入口参数:row:行,row=1表示第一行,row=2表示第二行
*          col:列,0~15,用于指定显示的列,范围可以是0~40
*出口参数:无
*********************************************************************/
void LCD_Setpos(uchar row,uchar col)
{
if(row==1) LCD_Writecmd(col | 0x80);
else LCD_Writecmd(col | 0xC0);
}
/*********************************************************************
*功能:显示一个字符   
*入口:ch:待显示的字符
*********************************************************************/
void LCD_DispChar(char ch)
{
LCD_Writedata(ch);
}
/*********************************************************************
*功能:在指定位置显示一个字符   
*入口:row:行 1或2      col:列,0~15
*      ch:待显示的字符
*********************************************************************/
void LCD_Setpos_DispChar(uchar row,uchar col,char ch)
{
LCD_Setpos(row,col);
LCD_Writedata(ch);
}
/*********************************************************************
*名    称:LCD_DispString()
*功    能:使LCD1602显示一个字符串,显示位置需提前设定
*入口参数:str[]:待显示的字符串
*出口参数:无
*********************************************************************/
void LCD_DispString(char str[])
{
    uchar i=0;
while(str != '\0')
{
    LCD_Writedata(str);
    ++i;
}
}
/*********************************************************************
*名    称:LCD_Setpos_DispString()
*功    能:使LCD1602从指定位置开始显示一个字符串
*入口参数:row:显示行,1或2
*          col:显示列,0~15 (0~40)
*          str[]:待显示的字符串
*出口参数:无
*说    明:指定位置是显示的初始位置,第一个字符显示的位置
*********************************************************************/
void LCD_Setpos_DispString(uchar row,uchar col,char str[])
{
LCD_Setpos(row,col);
LCD_DispString(str);
}
/*********************************************************************
*名    称:LCD_Dispnum()
*功    能:显示一个不超过8位的整数,显示位置需提前设置
*入口参数:num:待显示的整数,不超过8位
*出口参数:无
*********************************************************************/
void LCD_Dispnum(uint32_t num)
{
   uint i=0,j,k=0,wei,q;
   char str;
   if(num>=10000000)wei=8;
   else if(num>=1000000)wei=7;
   else if(num>=100000)wei=6;
   else if(num>=10000)wei=5;
   else if(num>=1000) wei=4;
   else if(num>=100)wei=3;
   else if(num>=10) wei=2;
   else wei=1;
   for(i=wei;i>0;i--)
   {   q=1;
       j=1; //i=1时,q=1,得到个位
    for(;j<i;j++)
    q*=10;               
                str=num/q +'0';
    num %= q;
   }
   str = '\0'; //添加字符串结束标志
   LCD_DispString(str);//显示字符串
}
/*********************************************************************
*名    称:LCD_Setpos_Dispnum()
*功    能:在指定位置显示一个不超过8位的整数
*入口参数:num:待显示的整数,不超过8位
*出口参数:无
*********************************************************************/
void LCD_Setpos_Dispnum(uchar row,uchar col,uint32_t num)
{
   LCD_Setpos(row,col);
   LCD_Dispnum(num);
}
/*********************************************************************
*名    称:LCD_DispDecimal()
*功    能:显示一个有效位不超过8位的浮点数,显示位置需要提前设定
*入口参数:num:待显示的浮点数放大后得到的整数,不超过8位
*          dot:小数点的位数
*出口参数:无
*********************************************************************/
void LCD_DispDecimal(uint32_t num,uchar dot)
{
   uint i=0,j,k=0,wei,q;
   char str;
   if(num>=10000000)wei=8;
   else if(num>=1000000)wei=7;
   else if(num>=100000)wei=6;
   else if(num>=10000)wei=5;
   else if(num>=1000) wei=4;
   else if(num>=100)wei=3;
   else if(num>=10) wei=2;
   else wei=1;
   for(i=wei;i>0;i--)
   {   q=1;
       j=1; //i=1时,q=1,得到个位
    for(;j<i;j++)
    q*=10;               
                str=num/q +'0';
    num %= q;
   }
   str = '\0'; //添加字符串结束标志
   for(i=8;i>0;i--)
   {   if((str>='0')&&(str<='9')) break;
   }
   str='\0';   //添加字符串结束符
   for(j=0;j<dot;j++,i--)   
         {
   str=str;
   }
   str='.';       //插入小数点
   LCD_DispString(str);//显示浮点小数
}


/*********************************************************************
*名    称:LCD_Setpos_DispDecimal()
*功    能:在指定位置显示一个有效位不超过8位的浮点数
*入口参数:row:待显示的行 1,2
*          col:待显示的列 0~15
*          num:待显示的浮点数放大10的整数倍后得到的整数,不超过8位
*          dot:小数点的位数
*出口参数:无
*********************************************************************/
void LCD_Setpos_DispDecimal(uchar row,uchar col,uint32_t num,uchar dot)
{
LCD_Setpos(row,col);
LCD_DispDecimal(num,dot);
}
/*********************************************************************
*名    称:LCD_DispFreq()
*功    能:显示频率计,动态自动调整频率显示
*入口参数:freq:可以显示8位整数表示的频率值,频率范围1Hz~99MHz
*出口参数:无
*说    明:入口的频率值单位是Hz,显示函数自动选择合适的显示方式
*          freq>=1000000显示成6位小数的MHz
*    elsefreq>=1000   显示成3位小数的KHz
*    elsefreq>=0      默认显示单位是Hz(三个区间互斥)
*********************************************************************/
void LCD_DispFreq(uint32_t freq)
{
LCD_Setpos(1,0);
LCD_DispString("Current Freq:");
LCD_Setpos(2,1); //显示位置
if(freq>=1000000)
{
LCD_DispDecimal(freq,6);
LCD_DispString("MHz");
}
else if(freq>=1000)
{
LCD_DispDecimal(freq,3);
LCD_DispString("KHz");
}
else { LCD_Dispnum(freq);
   LCD_DispString("Hz");
}
LCD_Setpos(2,14);
LCD_DispString("OK");
}
//屏幕整体左移一格,用于滚动显示
void LCD_ShiftLeft()
{
LCD_Writecmd(0x18);
}
//屏幕整体右移一格,用于滚动显示
void LCD_ShiftRight(void)
{
LCD_Writecmd(0x1C);
}
//清屏,清除显示
void LCD_Clear(void)
{
LCD_Writecmd(0x01);
}
//使光标还回原点位置
void LCD_Return(void)
{
LCD_Writecmd(0x02);
}
//关显示
void LCD_Close(void)
{
LCD_Writecmd(0x08);
}
//开显示
void LCD_Open(void)
{
LCD_Writecmd(0x0C);
}
/*********************************************************************
*名    称:LCD_FlickerChar()
*功    能:使指定位置字符闪烁,不显示光标
*入口参数:row:行 1,2
*          col:列 0~15
*出口参数:无
*说    明:写命令0x0D不显示光标的闪烁,写命令0x0F是显示光标的闪烁
*          一旦设定闪烁后,会根据位置变化闪烁,关闪烁写命令0x0C
*********************************************************************/
void LCD_FlickerChar(uchar row,uchar col)
{
LCD_Writecmd(0x0D);
LCD_Setpos(row,col);
}
//关闭字符闪烁
void LCD_CloseFlicker(void)
{
LCD_Writecmd(0x0C);
}
//屏幕秒闪烁一次
void LCD_FlickerScreen(void)
{
LCD_Writecmd(0x08);//关显示
delay_nms(500);
LCD_Writecmd(0x0C);//开显示
delay_nms(500);
}


/*********************************************************************
*名    称:LCD_Init()
*功    能:初始化LCD1602
*入口参数:无
*出口参数:无
*常用命令:0x38:16*2显示,5*&点阵显示字符,8位数据;指令执行时间40us
*          0x0C:开显示,关光标   40us
*          0x08:关显示,关光标   40us
*          0x0D:字符闪烁,关光标,接着设定位置,闪烁周期0.4ms左右
*          0x0F:字符闪烁,开光标
*          0x06:写完数据自动右移光标,普通情形,从左向右显示40us
*          0x04:写完数据自动左移光标,可以从右向左显示40us
*          0x01:清除显示内容,即清屏1.64ms
*          0x02:使光标还回起始位置   1.64ms
*          0x18:屏幕上所有字符同时左移一格,适合滚动显示 40us
*          0x1C:屏幕上所有字符同时右移一格,适合滚动显示 40us
*********************************************************************/
void LCD_Init(void)
{   
delay_nms(200);         //延时20ms         
LCD_WriteInitcmd(0x38);//16*2显示,5*7点阵,8位数据
delay_nms(10);
LCD_WriteInitcmd(0x38);//16*2显示,5*7点阵,8位数据
delay_nms(5);
LCD_WriteInitcmd(0x38);//16*2显示,5*7点阵,8位数据
delay_nms(5);
LCD_WriteInitcmd(0x08);//先关显示,后开显示
delay_nms(5);
LCD_WriteInitcmd(0x06);//自动右移光标,0x04为左移光标
delay_nms(5);
LCD_WriteInitcmd(0x01);//清除LCD的显示内容
delay_nms(6);
LCD_WriteInitcmd(0x0c);//显示开,关光标;0x08为关显示
delay_nms(5);
}

#endif//防止多次编译



/**********主函数main.c****************/
#include "stm32f30x.h"
#include "delay.h"
#include "sys.h"
//#include "usart.h"
//#include "led.h"
#include "lcd1602.h"
//#define PE00 (uint32_t *)0x40230180


//时钟配置函数 8MHz*9=72MHz
void RCC_Configuration()
{
    RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON);//使能HSE
if(RCC_WaitForHSEStartUp()==SUCCESS)
{
    RCC_HCLKConfig(RCC_SYSCLK_Div1); //HCLK=SYSCLK
    RCC_PCLK2Config(RCC_HCLK_Div1);
    RCC_PCLK1Config(RCC_HCLK_Div2);
    RCC_PLLConfig(RCC_PLLSource_HSI,RCC_PLLMul_9);
    RCC_PLLCmd(ENABLE);
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET);
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    while(RCC_GetSYSCLKSource()!=0x08);
}
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOA,ENABLE);//使能PA PB时钟
}

//延时 us
void delay_nus(unsigned long n)
{
unsigned long j;
while(n--)
{ j=8;
   while(j--);
}
}

//延时 ms
void delay_nms(unsigned long n)
{
while(n--)
    delay_nus(1100);
}
//GPIO配置
void GPIO_Configuration(void)
{
      GPIO_InitTypeDef      GPIO_InitStructure;
      
      //RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOA,ENABLE);//使能PB,PA端口时钟

      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出
      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;      //IO口速度为10MHz
      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//无上下拉
      GPIO_Init(GPIOA, &GPIO_InitStructure);                              //初始化GPIOA0~7

      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15|GPIO_Pin_14|GPIO_Pin_13;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出
      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;      //IO口速度为10MHz
      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//无上下拉
      GPIO_Init(GPIOB, &GPIO_InitStructure);                              //初始化GPIB15,14,13
}
int main()
{
    char str[]={"happy!"};
    RCC_Configuration();
    GPIO_Configuration();
    LCD_Init();
    LCD_Setpos_DispString(1,3,str);
                LCD_DispFreq(123456);
                LCD_FlickerChar(2,3);
                LCD_FlickerScreen();
                LCD_FlickerScreen();
                LCD_FlickerScreen();
                delay_nms(2000);
                LCD_CloseFlicker();
                while(1)
                {
                  ;
                }
}

2958155267 发表于 2015-10-27 08:57:09

1602电压是不是3.3v的

moyanming2013 发表于 2015-7-4 14:38:25

外加的一个LCD么,是否没移植好?

加拿大 发表于 2015-7-4 15:13:54

moyanming2013 发表于 2015-7-4 14:38
外加的一个LCD么,是否没移植好?

恩,都设置好了,硬件也连接没错,搞不清哪里问题?:L

wenyangzeng 发表于 2015-7-4 15:51:05

本帖最后由 wenyangzeng 于 2015-7-4 15:53 编辑

你在判断忙信号时貌似未将PA的D7位置为输入状态?另外语句DATAOUT(dat);看不出如何将dat送给PA口的D7-D0

lkl0305 发表于 2015-7-4 22:16:54

帮顶   

你好我好大家好! 发表于 2015-7-5 08:10:52

妈的,帮顶

beyondcore 发表于 2015-10-25 17:46:45

绑定:):):):)

csg123 发表于 2018-7-18 09:11:21

是否没移植好

glenxu 发表于 2020-5-25 08:33:42

没看见你的初始化程序,0x38 后面需要等待至少15ms,而不是40us,建议改40ms试试
页: [1]
查看完整版本: STM32F303+LCD1602程序问题,不只为什么点不亮?