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)
{
;
}
}
1602电压是不是3.3v的 外加的一个LCD么,是否没移植好? moyanming2013 发表于 2015-7-4 14:38
外加的一个LCD么,是否没移植好?
恩,都设置好了,硬件也连接没错,搞不清哪里问题?:L 本帖最后由 wenyangzeng 于 2015-7-4 15:53 编辑
你在判断忙信号时貌似未将PA的D7位置为输入状态?另外语句DATAOUT(dat);看不出如何将dat送给PA口的D7-D0
帮顶 妈的,帮顶 绑定:):):):) 是否没移植好 没看见你的初始化程序,0x38 后面需要等待至少15ms,而不是40us,建议改40ms试试
页:
[1]