本帖最后由 crazyfool 于 2020-4-5 22:52 编辑
//************************************************************
// Copyright (c) 深圳市赛元微电子有限公司
// 文件名称 : main.c
// 作者 :
// 模块功能 : LCD 显示code
// 局部函数列表:
// 最后更正日期:
// 版本 : V1.0
// 更改记录 : rom前256byte禁止查表,因此在编译的时候,设置keil->option for Target->BL51 Locate->Code Range:0x100
//*************************************************************
#include "LCD_INIT.h"
/*
本测试电路使用的LCD与MCU的连接是:
COM1 C4 P34
COM2 C5 P35
COM3 C6 P36
COM4 C7 P37
SEG1 S0 P33
SEG2 S1 P32
SEG3 S2 P31
SEG4 S3 P30
SEG5 S4 P10
SEG6 S6 P12
SEG7 S8 P14
SEG8 S9 P15
可见,硬件上,COM注意要么接在COM0-COM3要么接在COM4-COM7,但SEG口随意
根据上述接线,要配置对应IO口为LCD输出
下面寄存器
DDRCON
OTCON
要根据LCD的实际参数而配置
** LCD规格:1/4 duty 1/3bias 3.3V
*/
void LCD_Init(void) //DDIC配置为LCD,显示函数和配置需根据LCD屏进行修改
{
DDRCON = 0xB0; //-xyy zzzz x:LCD/LED模式 y:占空比 z:LCD电压调节
P0VO = 0x00;
P1VO = 0x35;
P2VO = 0x00;
P3VO = 0xFF;
OTCON = 0x04; //---- xxyz x:LCD分压电阻 y:复位管脚选择 z:LCD偏置电压
}
//************************************************************
// Copyright (c) 深圳市赛元微电子有限公司
// 文件名称 : LCD_DISPLAY.c
// 作者 :
// 模块功能 : LCD 显示
// 局部函数列表:
// 最后更正日期:
// 版本 : V1.0
// 更改记录 : rom前256byte禁止查表,因此在编译的时候,设置keil->option for Target->BL51 Locate->Code Range:0x100
//*************************************************************
#include "lcd_display.h"
static unsigned char xdata Display_Mode = 0;//0时钟 1NTC温度 2电压值 3DS18B20温度
//-----------------------LCD编码表---------------------------
static unsigned char code LcdCodeTab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00,0xff};
//-----------------------编码表下标数据-----------------------
static unsigned char xdata LcdDataTab[4] = {0,0,0,0};//即LCD待显示的数字
//-----------------------LCD显示RAM配置-----------------------
static unsigned char xdata LcdDisplay[28] _at_ 0x1000; //注意:不同LCD的RAM起始地址不同
//-----------------------数据各位缓存变量
static unsigned char xdata SEGA,SEGB,SEGC,SEGD,SEGE,SEGF,SEGG,SEGDP;//8个段不是有规律分配,需要处理
/**************************************************
*函数名称:void LcdSegData(unsigned char LcData,LcdSelCOM COMx)
*函数功能:LCD显示数据转换
*入口参数:LcdData LCD显示数据
COMx COM口选择(取值范围:LCDCOM0~7)
*出口参数:void
*功能说明:LcdDisplay[]数组下标值必须根据所选择的SEG口对应
**特别解读:程序中的COMx == LCDCOM0 等仅仅表示要写第几个位
并将数据写入对应的RAM区,仅仅是为了确定RAM地址
** LCD规格:1/4 duty 1/3bias 3.3V
**************************************************/
static void LcdSegData(unsigned char LcdData,LcdSelCOM COMx)
{
switch(Display_Mode)
{
case 0://时钟
if(COMx == LCDCOM0)
{
LcdData |= 0x80;//显示冒号
}
break;
case 1://NTC
if(COMx == LCDCOM0)
{
LcdData = 0;//不显示
}
if(COMx == LCDCOM1)
{
LcdData = 0;//不显示
}
break;
case 2://电压值
if(COMx == LCDCOM0)
{
LcdData = 0;//不显示
}
if(COMx == LCDCOM2)
{
LcdData |= 0x80;//显示小数点
}
break;
case 3://DS18B20温度
if(COMx == LCDCOM0)
{
LcdData = 0;//不显示
}
if(COMx == LCDCOM1)
{
LcdData = 0;//不显示
}
break;
default:break;
}
//如下四段,连在一个SEG
SEGA = ((LcdData >> 0) & 0X01) << 4;
SEGF = ((LcdData >> 5) & 0X01) << 5;
SEGE = ((LcdData >> 4) & 0X01) << 6;
SEGDP = ((LcdData >> 7) & 0X01) << 7;
//如下四段,连在一个SEG
SEGB = ((LcdData >> 1) & 0X01) << 4;
SEGG = ((LcdData >> 6) & 0X01) << 5;
SEGC = ((LcdData >> 2) & 0X01) << 6;
SEGD = ((LcdData >> 3) & 0X01) << 7;
//发送第0个字符对应的显示RAM区
if(COMx == LCDCOM0)
{
LcdDisplay[0] = (0x00 |SEGA | SEGF | SEGE | SEGDP);
LcdDisplay[1] = (0x00 |SEGB | SEGG | SEGC | SEGD);
}
//发送第1个字符对应的显示RAM区
if(COMx == LCDCOM1)
{
LcdDisplay[2] = (0x00 |SEGA | SEGF | SEGE | SEGDP);
LcdDisplay[3] = (0x00 |SEGB | SEGG | SEGC | SEGD);
}
//发送第2个字符对应的显示RAM区
if(COMx == LCDCOM2)
{
LcdDisplay[4] = (0x00 |SEGA | SEGF | SEGE | SEGDP);
LcdDisplay[6] = (0x00 |SEGB | SEGG | SEGC | SEGD);
}
//发送第3个字符对应的显示RAM区
if(COMx == LCDCOM3)
{
LcdDisplay[8] = (0x00 |SEGA | SEGF | SEGE | SEGDP);
LcdDisplay[9] = (0x00 |SEGB | SEGG | SEGC | SEGD);
}
}
/**************************************************
*函数名称:void LcdDisplay(void)
*函数功能:LCD显示
*入口参数:无
*出口参数:void
*功能说明:COM口必须跟使用的COM相对应
**************************************************/
void Lcd_Display(void)
{
switch(Display_Mode)
{
case 0://RTC 注意SEG1的P1段要点亮
LcdDataTab[0] = DS1302_Tab[2] >> 4;//时
LcdDataTab[1] = DS1302_Tab[2] & 0x0f;
LcdDataTab[2] = DS1302_Tab[1] >> 4;//分
LcdDataTab[3] = DS1302_Tab[1] & 0x0f;
break;
case 1://NTC温度
LcdDataTab[0] = 0;
LcdDataTab[1] = 0;
LcdDataTab[2] = NTC_Val / 10;
LcdDataTab[3] = NTC_Val % 10;
break;
case 2://电压值
LcdDataTab[0] = 0;
LcdDataTab[1] = Voltage_Val / 100;
LcdDataTab[2] = Voltage_Val % 100 / 10;
LcdDataTab[3] = Voltage_Val % 10;
break;
case 3://DS18B20温度值
LcdDataTab[0] = 0;
LcdDataTab[1] = 0;
LcdDataTab[2] = DS18B20_Val / 10;
LcdDataTab[3] = DS18B20_Val % 10;
break;
default:
Display_Mode = 0;
break;
}
LcdSegData(LcdCodeTab[LcdDataTab[0]],LCDCOM0);//发送第0个字符对应的RAM
LcdSegData(LcdCodeTab[LcdDataTab[1]],LCDCOM1);//发送第1个字符对应的RAM
LcdSegData(LcdCodeTab[LcdDataTab[2]],LCDCOM2);//发送第2个字符对应的RAM
LcdSegData(LcdCodeTab[LcdDataTab[3]],LCDCOM3);//发送第3个字符对应的RAM
}
/**************************************************
*函数名称:void Dis_Mode_Handle(void)
*函数功能:LCD显示模式处理
*入口参数:无
*出口参数:void
*功能说明:通过TK24实现改变显示模式
**************************************************/
void Dis_Mode_Handle(void)
{
Display_Mode ++;
if(Display_Mode > 3)
{
Display_Mode = 0;
}
}
#include "TK_Handle.H"
/*
特别说明:原理图设计时,标注有误
电路板上的TK27对应真实TK24 TK26对应真实TK25
短按分别选择显示内容 RGB颜色码
长按TK25改变占空比
*/
#define TK24 0x01000000 //TK24用以改变LCD显示模式【变量定义在LCD_DISPLAY.C中】
#define TK25 0x02000000 //TK25用以切换RGB色
static unsigned long xdata exKeyValueFlag = 0; //当前轮按键标志
static unsigned char xdata KeyValid_Flag = 0; //按键有效标志,蜂鸣器响0.1s
static unsigned char xdata RGB_Code = 1; //RGB颜色码,0-7对应不同颜色
static unsigned char xdata PWM_Dudy = 2; //PWM占空比,步长为2%,为避免太刺眼,限制在20%
/*****************************************************
*函数名称:void TK_Init(void)
*函数功能:触摸按键初始化 - 调用库函数
*入口参数:void
*出口参数:void
** 再封装,此为第一步,在系统初始化时调用
** 注意初始化持续几百毫秒,建议先于定时器 WDT等前初始化
*****************************************************/
void TK_Init(void)//触控按键初始化
{
TouchKeyInit();
}
/**************************************************
*函数名称:void TK_Scan(void)
*函数功能:扫描TK和显示
*入口参数:void
*出口参数:void
** 每10ms调用一次
**************************************************/
void TK_Scan(void)
{
if(SOCAPI_TouchKeyStatus&0x80) //重要步骤2:触摸键扫描一轮标志,是否调用TouchKeyScan()一定要根据此标志位置起后
{
SOCAPI_TouchKeyStatus &= 0x7f; //重要步骤3: 清除标志位, 需要外部清除。
exKeyValueFlag = TouchKeyScan();//按键数据处理函数
TouchKeyRestart(); //启动下一轮转换
}
}
/**************************************************
*函数名称:void TK_Handle(void)
*函数功能:TK按键处理函数
*入口参数:void
*出口参数:void
** 每10ms调用一次,建议紧随在TK_Scan函数之后
**************************************************/
void TK_Handle(void)
{
static bit TK24_Flag = 0,TK25_Flag = 0;//按键标志,只响应短按
static unsigned int xdata Time_Cnt = 0;//长按标志,0.3s有效
if((exKeyValueFlag & TK24) == TK24)
{
if(TK24_Flag == 0)
{
TK24_Flag = 1;
KeyValid_Flag = 1;
Dis_Mode_Handle();
}
}
else
{
TK24_Flag = 0;
}
if((exKeyValueFlag & TK25) == TK25)
{
if(TK25_Flag == 0)
{
TK25_Flag = 1;
Time_Cnt = 0;
KeyValid_Flag = 1;
RGB_Code ++;
if(RGB_Code > 7)
{
RGB_Code = 1;
}
}
else if( ++Time_Cnt >= 30)
{
Time_Cnt = 0;
PWM_Dudy += 2;
if(PWM_Dudy > 20)
{
PWM_Dudy = 2;
}
}
}
else
{
TK25_Flag = 0;
Time_Cnt = 0;
}
}
/**************************************************
*函数名称:void Buzzer_Handle(void)
*函数功能:蜂鸣器响0.1s
*入口参数:void
*出口参数:void
** 每20ms调用一次
**************************************************/
void Buzzer_Handle(void)
{
static unsigned char xdata Time_Cnt = 0;
if(KeyValid_Flag > 0)
{
Buzzer_Switch(1);
Time_Cnt ++;
if(Time_Cnt > 5)
{
Time_Cnt = 0;
Buzzer_Switch(0);
KeyValid_Flag = 0;
}
}
}
/**************************************************
*函数名称:void RGB_Handle(void)
*函数功能:RGB显示函数,这里只显示颜色,未改变占空比【固定】
*入口参数:void
*出口参数:void
** 每20ms调用一次
extern void RGB_R_Switch(unsigned int Duty_Val);
extern void RGB_G_Switch(unsigned int Duty_Val);
extern void RGB_B_Switch(unsigned int Duty_Val);
**************************************************/
void RGB_Handle(void)
{
switch(RGB_Code)
{
case 0:
RGB_R_Switch(0);
RGB_G_Switch(0);
RGB_B_Switch(0);
break;
case 1:
RGB_R_Switch(PWM_Dudy);
RGB_G_Switch(0);
RGB_B_Switch(0);
break;
case 2:
RGB_R_Switch(0);
RGB_G_Switch(PWM_Dudy);
RGB_B_Switch(0);
break;
case 3:
RGB_R_Switch(0);
RGB_G_Switch(0);
RGB_B_Switch(PWM_Dudy);
break;
case 4:
RGB_R_Switch(PWM_Dudy);
RGB_G_Switch(PWM_Dudy);
RGB_B_Switch(0);
break;
case 5:
RGB_R_Switch(PWM_Dudy);
RGB_G_Switch(0);
RGB_B_Switch(PWM_Dudy);
break;
case 6:
RGB_R_Switch(0);
RGB_G_Switch(PWM_Dudy);
RGB_B_Switch(PWM_Dudy);
break;
case 7:
RGB_R_Switch(PWM_Dudy);
RGB_G_Switch(PWM_Dudy);
RGB_B_Switch(PWM_Dudy);
break;
default:break;
}
}
一、板载资源
1.电位器 - AIN3(与2实现多通道切换)测试ADC功能
2.NTC - AIN2 (与1实现多通道切换)实现廉价测温,使用乘除法器实现数据计算。这里只简单查表0-40°温度。
3.无源蜂鸣器 - PWM40 测试PWM
4.4个LED灯 - PWM50 - PWM53,可测试PWM、可作为TK指示灯
5.RGB灯珠(5050) - PWM41 -PWM42 ,测试PWM,颜色选择、占空比调节(测试TK长按功能)
6.DS18B20 - 单总线数字温度传感器,时序要求严格,测试定时器、IO口方向动态改变(输入输出快速切换),并与NTC测温做比较
7.4路TK - TK24 - TK27,这是重点之一,熟悉TK调试使用基本流程。
8.DS1302 - RTC,测试LCD,并用UART0实现RTC调整(带后备电池,可断电运行)
9.LCD - 4COM,8SEG,1/4占空比,1/3偏压,3.3V 测试硬件LCD功能。这是重点之二。
二、个人遇到的几个坑
1.PWM的占空比设定值注意不能超过PWM周期,假设周期为2000个数,则占空比应在0-2000之间设定;本人一开始,以12位PWM对应范围0-4095进行设置,以致无法实现预期的占空比调节。
2.TK设计时,对新手或不熟悉的用户来说,应充分阅读学习设计指南。比如走线、线距、敷铜等操作。
3.赛元单片机的GPIO有三种模式(推挽输出、高阻输入(上电默认)、上拉输入),无开漏输出(可程序实现),也不具备准双向功能,当某个IO口同时要作为输入输出时,应注意根据需要改变方向设置。
4.未用IO或封装未引出IO,都要设为推挽输出。
5.TK功能的IO要设为推挽输出,并且直接输出1。
6.使用T1作为串口0的波特率,注意不能启动T1,即TR1不能设为1。
7.官方给的8617Demo程序,定时器初始化部分,应该有误,此型号HRC为32MHz,不是16MHz
8.LCD在硬件设计时,对4COM的LCD而言,COM口只能分配在COM0 - COM3 或 COM4 - COM7,不能随意分配,但分配好COM之余,SEG则可以根据布局需要,随意分配,只需注意对应的型号的单片机的RAM区起始地址。然后根据LCD手册对应段所在位置(接在哪个SEG上,适当处理后,往对应的RAM地址丢数据即可;但这里要注意,如果COM接在COM0-COM3则对应RAM的低4位有效,若是接在COM4-COM7,则是对应RAM的高4位有效。
三、致谢
1.此硬件为第1版,期间多次请教网友、赛元技术支持、康力佳FAE,再次深表感谢!本人能力有限,未能全部领悟,请多包涵。
2.欢迎交流,请勿喷——我这个中年男子。
|