头文件:
#ifndef _SMS0658B_LCD_H_
#define _SMS0658B_LCD_H_
/*
=========================================================================================================
SMS0658B 段式液晶结构图:
___A___
| |
F B
| |
---G---
| |
E C
|___D___| . --> H
例如: 如果要显示 '8', 则是 0xFE(从最高位到最低位一次是 FGEDABCH, 最低位表示小数点是 H).
再如: 显示 '4.', 则是 0xC6 | 0x01. 所以可根据上面的段序来组合意中的数字
=========================================================================================================
*/
//=========================================================================================================
// LCD 工作的配置信息常量
#define NOP10() {_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();}
#define NOP() {NOP10(); NOP10(); NOP10(); NOP10(); NOP10(); NOP10(); NOP10(); NOP10(); NOP10(); NOP10();}
// 显示小说点的掩码, H 位
#define DOT_MASK 0x01
// 空白显示
#define SPACE table[10]
// 下面是针对每个 LCD 的段选地址进行常量化
#define SEG_1 0
#define SEG_2 2
#define SEG_3 4
#define SEG_4 6
#define SEG_5 8
#define SEG_6 10
// LCD 序号
#define LCD_1 1
#define LCD_2 2
#define LCD_3 3
#define LCD_4 4
//=========================================================================================================
// 接口声明
// 液晶显示控制器进入睡眠模式以减少功耗
void LCD_Sleep(unsigned char n);
// LCD 初始化, 复位
void LCD_Reset(unsigned char n);
// LCD 频率显示函数
void LCD_Display_FRQ(unsigned int num, unsigned char n);
#endif
C文件:
#include <c8051f120.h>
#include <intrins.h>
#include "SMS0658B_LCD.h"
//=========================================================================================================
// 控制命令字
#define CMDOFF 0x00
#define CMDON 0x01
#define CMDLCDOFF 0x02
#define CMDLCDON 0x03
#define CMDB3C4 0x29
//SMS0658B 引脚说明
//PIN1: CS [片选信号输入]
//PIN2: CLK [串行移位脉冲输入]
//PIN3: DI [串行数据输入]
//PIN4: VSS [电源地]
//PIN5: VDD [电源正极]
// 1 <= n <= 4
#define CS_SET(n) (P4 |= 1 << n) // 设置某位置高
#define CS_CLR(n) (P4 &= ~(1 << n)) // 清零某位置低
#define CS_FALLING_EDGE(n) {CS_SET(n); NOP(); NOP(); CS_CLR(n); NOP(); NOP(); } // 第 n 位引脚下降沿产生
// 数据和串行时钟引脚
sbit DIPIN = P0^5;
sbit CLKPIN = P0^6;
// 0 1 2 3 4 5 6 7 8 9 空白 -
unsigned char code table[] = {0xBE, 0x06, 0x7C, 0x5E, 0xC6, 0xDA, 0xFA, 0x0E, 0xFE, 0xCE, 0xBE, 0x40};
//=========================================================================================================
// 送入 1 位数据到 LCD 显示控制器
static void Trans_Bit(bit bit_data)
{
DIPIN = bit_data; // 送入数据到串行输入口 DI
NOP();
CLKPIN = 1; // 时钟端口发送一个负脉冲
NOP();
CLKPIN = 0;
NOP(); // 延时一会儿
CLKPIN = 1;
}
//=========================================================================================================
// 送控制字到液晶显示控制器
// 参数: n表示选中的 LCD 序号
static void LCD_WC(unsigned char cmd, unsigned char n)
{
unsigned char i = 0;
// 参数检查
if (n > 4 || n < 1) {
return ; // LCD 序号错误
}
CS_FALLING_EDGE(n); // CS 先产生下降沿
Trans_Bit(1); // 连续送入数据 100b 后再送入控制命令
NOP();
Trans_Bit(0);
NOP();
Trans_Bit(0);
NOP();
for (i = 0; i < 8; i++) {
if((cmd & 0x80) == 0x80) {
Trans_Bit(1);
}
else {
Trans_Bit(0);
}
cmd <<= 1;
NOP();
}
Trans_Bit(0);
NOP();
DIPIN = 1;
CS_SET(n); // 送完后将对应的 LCD 片选端置高
}
//=========================================================================================================
void LCD_Reset(unsigned char n)
{
// 参数检查
if (n > 4 || n < 1) {
return ; // LCD 序号错误
}
LCD_WC(CMDOFF, n); // 掉电
LCD_WC(CMDLCDOFF, n); // 关闭
LCD_WC(CMDON, n); // 上电
LCD_WC(CMDLCDON, n); // 显示
LCD_WC(CMDB3C4, n); // 模式设置
}
//=========================================================================================================
// 液晶显示控制器进入睡眠模式减少功耗
// 参数: n 表示将对应的 LCD 设为睡眠状态
void LCD_Sleep(unsigned char n)
{
// 参数检查
if (n > 4 || n < 1) {
return ; // LCD 序号错误
}
LCD_WC(CMDLCDOFF, n); // 关闭液晶显示
LCD_WC(CMDOFF, n); // 进入睡眠状态, 此时 LCD 控制器电流小于 1uA
}
//=========================================================================================================
// 发送 1 字节数据到液晶显示控制器
static void Trans_data(unsigned char address, unsigned char Byte_data, unsigned char n)
{
unsigned char i;
// 参数检查
if (n > 4 || n < 1) {
return ; // LCD 序号错误
}
CS_SET(n);
NOP();
CS_CLR(n);
Trans_Bit(1);
NOP();
Trans_Bit(0);
NOP();
Trans_Bit(1);
NOP();
// 地址处理
address <<= 2;
for (i = 0; i < 6; i++) {
if ((address & 0x80) == 0x80) {
Trans_Bit(1);
}
else {
Trans_Bit(0);
}
address <<= 1;
NOP();
}
// 送数据
for (i = 0; i < 8; i++) {
if ((Byte_data & 0x01) == 0x01) {
Trans_Bit(1);
}
else {
Trans_Bit(0);
}
Byte_data >>= 1;
NOP();
}
DIPIN = 1;
CS_SET(n);
}
//=========================================================================================================
// LCD 频率显示函数, 高位为零时显示空白, 其余正常显示 0
// 参数: freq 表示将要显示的频率值, n 表示送入第几个 LCD 显示.
// 输出: 无
// 注意: 如果, 将此函数放到定时中断内进行处理, 可能需要点时间, 影响其他操作的实时性. 所以, 尽量将
// 定时器中断频率降低, 不影响
void LCD_Display_FRQ(unsigned int freq, unsigned char n)
{
// 参数检查
if (n > 4 || n < 1) {
return ; // LCD 序号错误
}
if (freq > 137 || freq < 118) {
return ; // 频率超出界限, 根据设置而定
}
switch (n) {
case 1:
Trans_data(SEG_1, table[0], LCD_1); // 最低三位为精度根据情况, 暂时定为 0
Trans_data(SEG_2, table[0], LCD_1);
Trans_data(SEG_3, table[0], LCD_1);
Trans_data(SEG_4, table[freq % 10] | DOT_MASK, LCD_1); // 取个位显示, 后缀小数点
Trans_data(SEG_5, table[freq / 10 % 10], LCD_1); // 取十位显示
Trans_data(SEG_6, table[freq / 100], LCD_1);
break;
case 2:
Trans_data(SEG_1, table[0], LCD_2); // 最低三位为精度根据情况, 暂时定为 0
Trans_data(SEG_2, table[0], LCD_2);
Trans_data(SEG_3, table[0], LCD_2);
Trans_data(SEG_4, table[freq % 10] | DOT_MASK, LCD_2); // 取个位显示, 后缀小数点
Trans_data(SEG_5, table[freq / 10 % 10], LCD_2); // 取十位显示
Trans_data(SEG_6, table[freq / 100], LCD_2);
break;
case 3:
Trans_data(SEG_1, table[0], LCD_3); // 最低三位为精度根据情况, 暂时定为 0
Trans_data(SEG_2, table[0], LCD_3);
Trans_data(SEG_3, table[0], LCD_3);
Trans_data(SEG_4, table[freq % 10] | DOT_MASK, LCD_3); // 取个位显示, 后缀小数点
Trans_data(SEG_5, table[freq / 10 % 10], LCD_3); // 取十位显示
Trans_data(SEG_6, table[freq / 100], LCD_3);
break;
case 4:
Trans_data(SEG_1, table[0], LCD_4); // 最低三位为精度根据情况, 暂时定为 0
Trans_data(SEG_2, table[0], LCD_4);
Trans_data(SEG_3, table[0], LCD_4);
Trans_data(SEG_4, table[freq % 10] | DOT_MASK, LCD_4); // 取个位显示, 后缀小数点
Trans_data(SEG_5, table[freq / 10 % 10], LCD_4); // 取十位显示
Trans_data(SEG_6, table[freq / 100], LCD_4);
break;
default:
return;
}
}