📄 lcd.c
字号:
#include <p30f6014.h>
#include <spi.h>
#include <dsp.h>
#include "common.h"
#include "timers.h"
#include "procsignal.h"
#include "menu.h"
#include "gettime.h"
#include "lcd.h"
#define MAXCHARSPERLINE 20
char PendPos;
static unsigned char TxQueue[256]; ////必须定义为256个字节,以便指针ptr绕回。
static volatile unsigned char TxQHead;
static volatile unsigned char TxQTail;
static char PlotBuf[128];
static int PlotPos;
static char PixelSendState;
static char PendDir;
static char CurPendPos;
static char PendTimer;
static const char INPUT_STR[] = "Input Signal";
static const char SYNC_STR[] = "Seconds Sync";
static const char DATA_STR[] = "Data Bit";
//函数原型
void InitLcd(void);
void CursState(char state);
void WriteChar(char ch);
void Write4Hex(unsigned int val);
void Write2Hex(unsigned char val);
void Write2Dec(unsigned char val);
void WriteDec(unsigned int val);
void ClearLcd(void);
void ClearLcdLine(unsigned char y);
void WriteCStr(const char* ptr);
void SetLcdPos(unsigned char x, unsigned char y );
void PlotTime( int* pBuf );
void ServiceLCD(void);
void PlotPendulum( void );
static void WritePend(char new);
static void PutTxQ(unsigned char val);
// SPI2中断服务子程序
void __attribute__((__interrupt__)) _SPI2Interrupt(void)
{
if( TxQHead!=TxQTail )
{
if( !SPI2STATbits.SPITBF )
WriteSPI2( TxQueue[TxQTail++] );
}
SPI2STATbits.SPIROV = 0;
IFS1bits.SPI2IF = 0;
}
//初始化16x2点阵LCD子程序
void InitLcd(void)
{
TRISGbits.TRISG9 = 0; //LCD控制器选择行
PORTGbits.RG0 = 1;
TxQHead = 0;
TxQTail = 0;
CloseSPI2();
ConfigIntSPI2(SPI_INT_EN & SPI_INT_PRI_3);
OpenSPI2( FRAME_ENABLE_OFF &
ENABLE_SDO_PIN &
SPI_MODE16_OFF &
SPI_SMP_OFF &
SPI_CKE_OFF &
SLAVE_ENABLE_OFF &
CLK_POL_ACTIVE_HIGH &
MASTER_ENABLE_ON &
#if (CLOCK_FREQ == CLOCK_FREQ4XPLL)
SEC_PRESCAL_1_1 & //设定LCD时钟预设值
#else
SEC_PRESCAL_2_1 &
#endif
PRI_PRESCAL_64_1,
SPI_ENABLE &
SPI_IDLE_CON &
SPI_RX_OVFLOW_CLR
);
LATGbits.LATG9 = 0;
SemA.PlotActive = 0;
TimeDelay(2);
WriteSPI2(0x80); /复位显示
TimeDelay(2);
WriteSPI2(0x80); /复位显示
TimeDelay(2);
PendDir = 1;
PendPos = 0;
PendTimer = 0;
}
//把一个字节放到SPI2传输队列子程序
static void PutTxQ(unsigned char val)
{
DisableIntSPI2;
TxQueue[TxQHead] = val;
if( TxQTail == TxQHead++ )
{
SPI2STATbits.SPIROV = 0;
IFS1bits.SPI2IF = 1; //create fake IRQ to "prime the pump"
}
EnableIntSPI2;
}
//清LCD屏幕并设起始点为0子程序
void ClearLcd(void)
{
PutTxQ(0x82);
}
//光标的状态
void CursState(char state)
{
if(state==0)
{
PutTxQ(0x8B);
}
else
{
PutTxQ(0x8C);
PutTxQ(0xAD);
PutTxQ(0x03);
}
}
//清LCD的行y子程序
void ClearLcdLine(unsigned char y)
{
PutTxQ(0xA9);
PutTxQ(y);
}
//在当前光标位置写一个字符子程序
void WriteChar(char ch)
{
PutTxQ(0xA8);
PutTxQ(ch);
}
//写钟摆的位置
static void WritePend(char newpos)
{
PutTxQ(0xE6);
PutTxQ(' ');
PutTxQ(CurPendPos);
PutTxQ(3);
//
PutTxQ(0xE6);
if( (0==newpos) || (19==newpos) )
PutTxQ('*');
else
PutTxQ('-');
PutTxQ(newpos);
PutTxQ(3);
}
//在当前光标位置写一个常字符串子程序
void WriteCStr(const char* ptr)
{
unsigned int i=0;
char ch;
do
{
ch = ptr[i++];
if(ch==0)
break;
else
WriteChar(ch);
}while(i<MAXCHARSPERLINE);
}
//在LCD上把一个数值写为4个16进制格式子程序
void Write4Hex(unsigned int val)
{
char ch;
ch = (val>>12);
if(ch<=9)
ch += '0';
else
ch += 'A' - 10;
WriteChar(ch);
ch = (val>>8) & 0x0F;
if(ch<=9)
ch += '0';
else
ch += 'A' - 10;
WriteChar(ch);
ch = (val>>4) & 0x0F;
if(ch<=9)
ch += '0';
else
ch += 'A' - 10;
WriteChar(ch);
ch = val & 0x0F;
if(ch<=9)
ch += '0';
else
ch += 'A' - 10;
WriteChar(ch);
}
//在LCD上把一个数值写为2个16进制格式子程序
void Write2Hex(unsigned char val)
{
char ch;
ch = val>>4;
if(ch<=9)
ch += '0';
else
ch += 'A' - 10;
WriteChar(ch);
ch = val & 0x0F;
if(ch<=9)
ch += '0';
else
ch += 'A' - 10;
WriteChar(ch);
}
//在LCD上把一个数值写为10进制格式子程序
void Write2Dec(unsigned char val)
{
char ch;
ch = val/10;
val = val - 10*ch;
ch += '0';
WriteChar(ch);
ch = val;
ch += '0';
WriteChar(ch);
}
//在LCD上把一个数值写为10进制格式子程序
void WriteDec(unsigned int val)
{
char ch;
unsigned int tmp;
tmp = val;
ch = tmp/10000;
tmp = tmp - 10000*ch;
ch += '0';
WriteChar(ch);
ch = tmp/1000;
tmp = tmp - 1000*ch;
ch += '0';
WriteChar(ch);
ch = tmp/100;
tmp = tmp - 100*ch;
ch += '0';
WriteChar(ch);
ch = tmp/10;
tmp = tmp - 10*ch;
ch += '0';
WriteChar(ch);
ch = tmp;
ch += '0';
WriteChar(ch);
}
//设定LCD的坐标子程序
void SetLcdPos(unsigned char x, unsigned char y )
{
PutTxQ(0xC5);
PutTxQ(x);
PutTxQ(y);
}
//画钟摆子程序
void PlotPendulum( void )
{
if(++PendTimer == 5) // 50Hz分为10Hz
{
PendTimer = 0;
if(PendPos>19) //处理方向改变
PendDir = -1;
else
if(PendPos<0)
PendDir = +1;
else
if(MENU_MAIN == CurrentMenu)
{
WritePend(PendPos);
CurPendPos = PendPos;
}
PendPos = CurPendPos+PendDir;
}
}
//画时间函数
void PlotTime( int* pBuf )
{
int x;
int z;
if(!SemA.PlotActive)
{
if(0==LCDHoldoffCounter)
{
if(CurrentMenu==MENU_SIGNAL)
{
for(x=0; x<122; x++)
PlotBuf[x] = (char)(16 + (pBuf[x]>>11) );
PutTxQ(0x82); //清屏
SetLcdPos(0,0);
WriteCStr(INPUT_STR);//画字符
PlotPos = 0;
PixelSendState = 0;
SemA.PlotActive = 1; //使能LCD画状态机
LCDHoldoffCounter = 4;
}
else if( SemA.SecRdy)
{
PutTxQ(0x82); //清屏
if( CurrentMenu==MENU_SYNC)
{
z = 150 - (122/2);
for(x=0; x<122; x++)
{
PlotBuf[x] = (char)( (SecSyncBuf[z]>>9) );
if(++z >= 150)
z = 0;
}
SetLcdPos(0,0); //画字符
WriteCStr(SYNC_STR);
}
else if( CurrentMenu==MENU_DATA )
{
for(x=0; x<122; x++)
PlotBuf[x] = (char)( (RawDataBuf[x/4]>>7) );
SetLcdPos(12,0); //画字符
WriteCStr(DATA_STR);
}
PlotPos = 0;
PixelSendState = 0;
SemA.PlotActive = 1; //使能LCD画状态机
LCDHoldoffCounter = 4;
}
}
}
}
//LCD画点子程序
void ServiceLCD( )
{
if( (TxQTail == TxQHead ) && SemA.PlotActive )
{
PixelSendState++;
if( PixelSendState==1 )
{
PutTxQ(0xD8); //像素开命令
}
else if( PixelSendState==2 )
{
PutTxQ(PlotPos ); //像素 x 位置写
}
else
{
PutTxQ(PlotBuf[PlotPos++] );
PixelSendState = 0; //像素 y 位置写
}
if(PixelSendState>=3)
PixelSendState = 0;
if( PlotPos>=122 )
SemA.PlotActive = 0;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -