打印
[应用相关]

STM32与BPC电波

[复制链接]
3734|27
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
STM32与BPC电波
我们通过电波钟模块接收国家授时中心发出的电波钟信号,通过STM32单片机将信号解码,就可以获得极为准确的时间信息。我的毕业设计中有一个模块是自动对时,在这里将我调出来的电波钟程序发出来,有感兴趣的或者设计需要电波钟的可以参考一下,节省开发时间。
沙发
wangjiahao88|  楼主 | 2018-11-2 13:26 | 只看该作者
一、电波钟介绍
电波钟是使用了低频授时技术进行对时的电子钟,更加详细的介绍可以查看 能够实现精确对时的电波钟(BPC)介绍 。

使用特权

评论回复
板凳
wangjiahao88|  楼主 | 2018-11-2 13:27 | 只看该作者
二、使用的元器件
STM32F103开发板

电波钟模块,可以在淘宝上买,价格在15元左右。

一些排针和杜邦线,由于连接电波钟模块

电波钟模块实物就是这样子的,一个小电路板以及一个磁棒。

使用特权

评论回复
地板
wangjiahao88|  楼主 | 2018-11-2 13:28 | 只看该作者
三、硬件设计
模块共有5个焊脚,在使用时只用到了V、G、T、P四个接口,具体的连接是:

V-接电源VCC,1.5~3.5V

G-接地GND

T-时间信号反向输出端

P-模块使能端,工作接底,静态接高

H-自动增益控制接高电平(模块已连好高电平,不用连接)

我将T端连到了PA0口,使用了STM32单片机的定时器2的通道1即TIM2_CH1,使用单片机的输入捕获,将信号进行解码。电波钟模块与STM32的连接原理图如下:

使用特权

评论回复
5
wangjiahao88|  楼主 | 2018-11-2 13:32 | 只看该作者
为什么不能上传图片了?

1.jpg (61.48 KB )

1.jpg

使用特权

评论回复
6
wangjiahao88|  楼主 | 2018-11-2 13:38 | 只看该作者
模块照片如下。

12.jpg (76.22 KB )

12.jpg

使用特权

评论回复
7
wangjiahao88|  楼主 | 2018-11-2 13:52 | 只看该作者
四、BPC编码格式

中国的 BPC 时间信号编码规则的特征是:

(1)每一帧信号的周期是 20 秒钟,所以每分钟可以发播 3 帧时间调制信号。

(2)脉冲周期是 1 秒钟,但是,脉冲宽度(即高电平持续时间)有四种,分别对应着四进制数的 0、1、2、3,脉宽400ms 对应 3,脉宽 300ms 对应 2,脉宽 200ms 对应 1,脉宽 100ms 对应 0。每帧时间信号包含 19个脉冲,缺少1个秒脉冲作为分隔,有规律的脉冲组合得以用来表示对应的时间信息。

(3)帧与帧的间隔,以缺少 1 秒脉冲方式表示。

P0:每帧的开始,每分钟 3 次,间隔 20 秒,因此 P0 则是在第 0 秒、第 20 秒和第 40 的位置。

P1:用做帧定位,P1 有三种状态,分别为 0、1、2,0 表示该帧从第 1 秒钟开始,1 表示该帧从第 21 秒钟开始,2 表示该帧从第 41 秒钟开始。

P2:保留帧,由于以后扩展,所以接收到的P2永远为0。

P3:组合使用位,前半位用于表示上午或下午,后半位用于第 0-8 位的偶校验,其中0,1表示上午,23表示下午。

P4:组合使用位,前半位保留,后半位用于第 10-17 位的偶校验。

使用特权

评论回复
8
wangjiahao88|  楼主 | 2018-11-2 13:52 | 只看该作者
可以看到,一帧的第4、5个脉冲表示当前的时,6、7、8脉冲表示当前的分钟信息,依次类推即可获得当前的时间信息,接收一帧完成后,根据P1 可以知道这一帧一分钟内的那一帧,从而可以获得当前的秒信息。


2.png (62.18 KB )

2.png

使用特权

评论回复
9
wangjiahao88|  楼主 | 2018-11-2 13:53 | 只看该作者
五、软件设计

使用keil 5进行程序开发,首先编写解码、显示程序,编译通过后将程序下载到单片机上运行,找到干扰较小的地方,就可以接收到BPC信号,从而获得当前的时间信息。输入捕获以及单片机对BPC信号进行解码的主要程序如下,要查看完整的文件,可以在**末尾下载我调好的工程文件,可以通过LCD显示屏查看时间,串口也会输出接收到的BPC信息。
输入捕获程序:

timer.c


#include "timer.h"
#include "led.h"
#include "usart.h"
#include "sys.h"
char BPC_Get_Status=0;
u8 bhour=0,bmin=0,bweek=0,bday=0,bmon=0,byear=0,wu=0,bsec=0;

//定时器2通道1输入捕获配置

TIM_ICInitTypeDef TIM2_ICInitStructure;

void TIM2_Cap_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能TIM2时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0 清除之前设置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_0);

//初始化定时器2 TIM2
TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频器
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

//初始化TIM2输入捕获参数
TIM2_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上
TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; //下降沿捕获
TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM2_ICInitStructure.TIM_ICFilter = 0x01;//IC1F=0000 配置输入滤波器 不滤波 //n=2 滤波
TIM_ICInit(TIM2, &TIM2_ICInitStructure);

//中断分组初始化
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级2级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级0级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断 ,允许CC1IE捕获中断

TIM_Cmd(TIM2,ENABLE ); //使能定时器2

}
u8 TIM2CH1_CAPTURE_STA=0; //输入捕获状态
u16 TIM2CH1_CAPTURE_VAL; //输入捕获值

//定时器2中断服务程序
void TIM2_IRQHandler(void)
{

if((TIM2CH1_CAPTURE_STA&0X80)==0)//还未成功捕获
{

//发生溢出后的情况
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)

{
if(TIM2CH1_CAPTURE_STA&0X40)//已经捕获到高电平了
{
if((TIM2CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
{
TIM2CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次
TIM2CH1_CAPTURE_VAL=0XFFFF;
}else TIM2CH1_CAPTURE_STA++;
}
}

//未发生溢出
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
{
if(TIM2CH1_CAPTURE_STA&0X40) //捕获到一个上降沿
{
TIM2CH1_CAPTURE_STA|=0X80; //标记成功捕获到一次上升沿
TIM2CH1_CAPTURE_VAL=TIM_GetCapture1(TIM2);
TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling); //CC1P=0 设置为上升沿捕获
}else //还未开始,第一次捕获上升沿
{
TIM2CH1_CAPTURE_STA=0; //清空
TIM2CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM2,0);
TIM2CH1_CAPTURE_STA|=0X40; //标记捕获到了上升沿
TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Rising); //CC1P=1 设置为下降沿捕获
}
}
}

TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位

}
     

使用特权

评论回复
10
wangjiahao88|  楼主 | 2018-11-2 13:53 | 只看该作者
主函数 main.c

   


#include "led.h"
#include "delay.h"
#include "sys.h"
#include "timer.h"
#include "usart.h"
#include "lcd.h"

extern u8 TIM2CH1_CAPTURE_STA; //输入捕获状态
extern u16 TIM2CH1_CAPTURE_VAL; //输入捕获值
char xiaoshi=0,fenzon=0,xinqi=0,ri=0,yue=0,nian=0,wu=0,miao=0;
int P1;
int i=0;
u8 a[19];
int main(void)
{

double temp=0;
int dat;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
delay_init(); //延时函数初始化
uart_init(9600); //9600
LED_Init(); //初始化与LED连接的硬件接口
LCD_Init();
TIM2_Cap_Init(0XFFFF,72-1); //以1Mhz的频率计数
POINT_COLOR=RED;
LCD_ShowString(50,130,200,16,16," - - ");
LCD_ShowString(60,80,200,24,24," : : ");

while(1)
{
delay_us(10);
if(TIM2CH1_CAPTURE_STA&0X80)//成功捕获到了一次高电平
{
miao=miao+1;
if(miao==60) miao=0;
temp=TIM2CH1_CAPTURE_STA&0X3F;
temp*=65536; //溢出时间总和
temp+=TIM2CH1_CAPTURE_VAL; //得到总的高电平时间
temp=(double)temp/1000; //ms
if((temp>=850)&&(temp<950)) dat=0;
else if((temp>=750)&&(temp<850)) dat=1;
else if((temp>=650)&&(temp<750)) dat=2;
else if((temp>=550)&&(temp<650)) dat=3;
if(temp>1200)
{
printf("\r\n");
i=0;
miao++;
LCD_ShowNum(128,80,miao,2,24);
}
a[i]=dat;
i++;
if(i==19)
{
xiaoshi=((a[3])*4)+(a[4]);
fenzon=(((a[5])*16)+((a[6])*4)+(a[7]));
xinqi=((a[8])*4)+(a[9]);
ri=((a[11])*16)+((a[12])*4)+a[13]; // 换算方式
yue=((a[14])*4)+a[15];
nian=((a[16])*16)+((a[17])*4)+a[18];
wu=a[10]; //0和1表示上午 2和3表示下午
P1=a[1]; // 0表示1秒 1表示21秒 2表示41秒
if(P1==0)
{
miao=19;
}
if(P1==1)
{
miao=39;
}
if(P1==2)
{
miao=59;
}
if(wu>1)
{
xiaoshi=xiaoshi+12; //时间处理
}
}

TIM2CH1_CAPTURE_STA=0; //开启下一次捕获
printf("%d ",dat);

LCD_ShowNum(50,130,nian,4,16);
LCD_ShowNum(90,130,yue,2,16);
LCD_ShowNum(114,130,ri,2,16);
switch(xinqi)
{
case 0:
LCD_ShowString(160,130,200,16,16,"Sunday ");
break;
case 1:
LCD_ShowString(160,130,200,16,16,"Monday ");
break;
case 2:
LCD_ShowString(160,130,200,16,16,"Tuesday ");
break;
case 3:
LCD_ShowString(160,130,200,16,16,"Wednesday");
break;
case 4:
LCD_ShowString(160,130,200,16,16,"Thursday ");
break;
case 5:
LCD_ShowString(160,130,200,16,16,"Friday ");
break;
case 6:
LCD_ShowString(160,130,200,16,16,"Saturday ");
break;
}

LCD_ShowNum(60,80,xiaoshi,2,24);
LCD_ShowNum(94,80,fenzon,2,24);
LCD_ShowNum(128,80,miao,2,24);
POINT_COLOR=GBLUE;
LCD_ShowxNum(10,10,dat,10,24,0);
POINT_COLOR=RED;

}
}
}
  

使用特权

评论回复
11
wangjiahao88|  楼主 | 2018-11-2 13:54 | 只看该作者
六、运行效果展示

基于STM32 单片机的自动对时电子钟



自动对时-2048x1152.jpg (357.26 KB )

自动对时-2048x1152.jpg

使用特权

评论回复
12
wangjiahao88|  楼主 | 2018-11-2 13:57 | 只看该作者
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "timer.h"
#include "usart.h"
#include "lcd.h"

extern u8  TIM2CH1_CAPTURE_STA;                //输入捕获状态                                                   
extern u16        TIM2CH1_CAPTURE_VAL;        //输入捕获值
char xiaoshi=0,fenzon=0,xinqi=0,ri=0,yue=0,nian=0,wu=0,miao=0;
int P1;
int i=0;
u8 a[19];
int main(void)
{       
         
        double temp=0;
        int dat;
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
        delay_init();                     //延时函数初始化       
        uart_init(9600);                                 //9600         
        LED_Init();                          //初始化与LED连接的硬件接口
        LCD_Init();
        TIM2_Cap_Init(0XFFFF,72-1);                //以1Mhz的频率计数
        POINT_COLOR=RED;
        LCD_ShowString(50,130,200,16,16,"    -  -     ");          
        LCD_ShowString(60,80,200,24,24,"  :  :    ");
       
           while(1)
        {
                delay_us(10);         
                if(TIM2CH1_CAPTURE_STA&0X80)//成功捕获到了一次高电平
                {
                        miao=miao+1;
                        if(miao==60) miao=0;
                        temp=TIM2CH1_CAPTURE_STA&0X3F;
                        temp*=65536;                                        //溢出时间总和
                        temp+=TIM2CH1_CAPTURE_VAL;                        //得到总的高电平时间
                        temp=(double)temp/1000; //ms
                        if((temp>=850)&&(temp<950)) dat=0;
                        else if((temp>=750)&&(temp<850)) dat=1;
                        else if((temp>=650)&&(temp<750)) dat=2;
                        else if((temp>=550)&&(temp<650)) dat=3;
                        if(temp>1200)
                        {
                                printf("\r\n");
                                i=0;
                                miao++;
                                LCD_ShowNum(128,80,miao,2,24);
                        }
                        a[i]=dat;
                        i++;
                        if(i==19)
                        {
                        xiaoshi=((a[3])*4)+(a[4]);
                        fenzon=(((a[5])*16)+((a[6])*4)+(a[7]));
                        xinqi=((a[8])*4)+(a[9]);
                        ri=((a[11])*16)+((a[12])*4)+a[13];           // 换算方式
                        yue=((a[14])*4)+a[15];
                        nian=((a[16])*16)+((a[17])*4)+a[18];
                        wu=a[10];            //0和1表示上午 2和3表示下午
                        P1=a[1];          // 0表示1秒 1表示21秒 2表示41秒
                        if(P1==0)
                        {   
                          miao=19;
                        }
                        if(P1==1)
                        {
                          miao=39;
                        }
                        if(P1==2)
                        {
                          miao=59;
                        }
                        if(wu>1)
                        {
                          xiaoshi=xiaoshi+12;      //时间处理
                        }
                        }
                       
                        TIM2CH1_CAPTURE_STA=0;                        //开启下一次捕获
                        printf("%d ",dat);
                       
                        LCD_ShowNum(50,130,nian,4,16);                                                                          
                        LCD_ShowNum(90,130,yue,2,16);                                                                          
                        LCD_ShowNum(114,130,ri,2,16);         
                        switch(xinqi)
                        {
                                case 0:
                                        LCD_ShowString(160,130,200,16,16,"Sunday   ");
                                        break;
                                case 1:
                                        LCD_ShowString(160,130,200,16,16,"Monday   ");
                                        break;
                                case 2:
                                        LCD_ShowString(160,130,200,16,16,"Tuesday ");
                                        break;
                                case 3:
                                        LCD_ShowString(160,130,200,16,16,"Wednesday");
                                        break;
                                case 4:
                                        LCD_ShowString(160,130,200,16,16,"Thursday ");
                                        break;
                                case 5:
                                        LCD_ShowString(160,130,200,16,16,"Friday   ");
                                        break;
                                case 6:
                                        LCD_ShowString(160,130,200,16,16,"Saturday ");
                                        break;  
                        }
               
                        LCD_ShowNum(60,80,xiaoshi,2,24);                                                                          
                        LCD_ShowNum(94,80,fenzon,2,24);                                                                          
                        LCD_ShowNum(128,80,miao,2,24);
                        POINT_COLOR=GBLUE;
                        LCD_ShowxNum(10,10,dat,10,24,0);
                        POINT_COLOR=RED;
               
                }
        }
}

使用特权

评论回复
13
wangjiahao88|  楼主 | 2018-11-2 13:58 | 只看该作者
//初始化PB5和PE5为输出口.并使能这两个口的时钟                    
//LED IO初始化
void LED_Init(void)
{

GPIO_InitTypeDef  GPIO_InitStructure;
       
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE);         //使能PA,PD端口时钟
       
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;                                 //LED0-->PA.8 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                 //IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure);                                         //根据设定参数初始化GPIOA.8
GPIO_SetBits(GPIOA,GPIO_Pin_8);                                                 //PA.8 输出高

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;                             //LED1-->PD.2 端口配置, 推挽输出
GPIO_Init(GPIOD, &GPIO_InitStructure);                                           //推挽输出 ,IO口速度为50MHz
GPIO_SetBits(GPIOD,GPIO_Pin_2);                                                  //PD.2 输出高
}

使用特权

评论回复
14
wangjiahao88|  楼主 | 2018-11-2 13:58 | 只看该作者
//LCD的画笔颜色和背景色          
u16 POINT_COLOR=0x0000;        //画笔颜色
u16 BACK_COLOR=0xFFFF;  //背景色

//管理LCD重要参数
//默认为竖屏
_lcd_dev lcddev;
                                                     
//写寄存器函数
//data:寄存器值
void LCD_WR_REG(u16 data)
{
        LCD_RS_CLR;//写地址  
        LCD_CS_CLR;
        DATAOUT(data);
        LCD_WR_CLR;
        LCD_WR_SET;
        LCD_CS_SET;   
}
//写数据函数
//可以替代LCD_WR_DATAX宏,拿时间换空间.
//data:寄存器值
void LCD_WR_DATAX(u16 data)
{
        LCD_RS_SET;
        LCD_CS_CLR;
        DATAOUT(data);
        LCD_WR_CLR;
        LCD_WR_SET;
        LCD_CS_SET;
}
//读LCD数据
//返回值:读到的值
u16 LCD_RD_DATA(void)
{                                                                                  
        u16 t;
        GPIOB->CRL=0X88888888; //PB0-7  上拉输入
        GPIOB->CRH=0X88888888; //PB8-15 上拉输入
        GPIOB->ODR=0X0000;     //全部输出0

        LCD_RS_SET;
        LCD_CS_CLR;
        //读取数据(读寄存器时,并不需要读2次)
        LCD_RD_CLR;
        if(lcddev.id==0X8989)delay_us(2);//FOR 8989,延时2us                                          
        t=DATAIN;  
        LCD_RD_SET;
        LCD_CS_SET;

        GPIOB->CRL=0X33333333; //PB0-7  上拉输出
        GPIOB->CRH=0X33333333; //PB8-15 上拉输出
        GPIOB->ODR=0XFFFF;    //全部输出高
        return t;  
}
//写寄存器
//LCD_Reg:寄存器编号
//LCD_RegValue:要写入的值
void LCD_WriteReg(u16 LCD_Reg,u16 LCD_RegValue)
{       
        LCD_WR_REG(LCD_Reg);  
        LCD_WR_DATA(LCD_RegValue);                             
}   
//读寄存器
//LCD_Reg:寄存器编号
//返回值:读到的值
u16 LCD_ReadReg(u16 LCD_Reg)
{                                                                                  
        LCD_WR_REG(LCD_Reg);  //写入要读的寄存器号  
        return LCD_RD_DATA();
}
//开始写GRAM
void LCD_WriteRAM_Prepare(void)
{
        LCD_WR_REG(lcddev.wramcmd);
}
//LCD写GRAM
//RGB_Code:颜色值
void LCD_WriteRAM(u16 RGB_Code)
{                                                            
        LCD_WR_DATA(RGB_Code);//写十六位GRAM
}
//从ILI93xx读出的数据为GBR格式,而我们写入的时候为RGB格式。
//通过该函数转换
//c:GBR格式的颜色值
//返回值:RGB格式的颜色值
u16 LCD_BGR2RGB(u16 c)
{
        u16  r,g,b,rgb;   
        b=(c>>0)&0x1f;
        g=(c>>5)&0x3f;
        r=(c>>11)&0x1f;         
        rgb=(b<<11)+(g<<5)+(r<<0);                 
        return(rgb);
}       
//当mdk -O1时间优化时需要设置
//延时i
void opt_delay(u8 i)
{
        while(i--);
}
//读取个某点的颜色值         
//x,y:坐标
//返回值:此点的颜色
u16 LCD_ReadPoint(u16 x,u16 y)
{
        u16 r,g,b;
        if(x>=lcddev.width||y>=lcddev.height)return 0;        //超过了范围,直接返回                  
        LCD_SetCursor(x,y);
        if(lcddev.id==0X9341||lcddev.id==0X6804||lcddev.id==0X5310||lcddev.id==0X1963)LCD_WR_REG(0X2E);//9341/6804/3510/1963 发送读GRAM指令
        else if(lcddev.id==0X5510)LCD_WR_REG(0X2E00);        //5510 发送读GRAM指令
        else LCD_WR_REG(0X22);                                               //其他IC发送读GRAM指令
        GPIOB->CRL=0X88888888;                                                         //PB0-7  上拉输入
        GPIOB->CRH=0X88888888;                                                         //PB8-15 上拉输入
        GPIOB->ODR=0XFFFF;                                                             //全部输出高

        LCD_RS_SET;
        LCD_CS_CLR;            
        //读取数据(读GRAM时,第一次为假读)       
        LCD_RD_CLR;                  
        opt_delay(2);                                                                        //延时               
        r=DATAIN;                                                                                  //实际坐标颜色
        LCD_RD_SET;
        if(lcddev.id==0X1963)
        {
                LCD_CS_SET;
                GPIOB->CRL=0X33333333;                 //PB0-7  上拉输出
                GPIOB->CRH=0X33333333;                 //PB8-15 上拉输出
                GPIOB->ODR=0XFFFF;                    //全部输出高  
                return r;                                        //1963直接读就可以
        }
        //dummy READ
        LCD_RD_CLR;                                          
        opt_delay(2);//延时                                          
        r=DATAIN;          //实际坐标颜色
        LCD_RD_SET;
        if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X5510)        //9341/NT35310/NT35510要分2次读出
        {         
                LCD_RD_CLR;                                          
                opt_delay(2);//延时                          
                b=DATAIN;//读取蓝色值            
                 LCD_RD_SET;
                g=r&0XFF;//对于9341,第一次读取的是RG的值,R在前,G在后,各占8位
                g<<=8;
        }else if(lcddev.id==0X6804)
        {
                LCD_RD_CLR;                                          
                 LCD_RD_SET;
                r=DATAIN;//6804第二次读取的才是真实值
        }         
        LCD_CS_SET;
        GPIOB->CRL=0X33333333;                 //PB0-7  上拉输出
        GPIOB->CRH=0X33333333;                 //PB8-15 上拉输出
        GPIOB->ODR=0XFFFF;                    //全部输出高  
        if(lcddev.id==0X9325||lcddev.id==0X4535||lcddev.id==0X4531||lcddev.id==0X8989||lcddev.id==0XB505)return r;        //这几种IC直接返回颜色值
        else if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X5510)return (((r>>11)<<11)|((g>>10)<<5)|(b>>11));//ILI9341/NT35310/NT35510需要公式转换一下
        else return LCD_BGR2RGB(r);        //其他IC
}                 
//LCD开启显示
void LCD_DisplayOn(void)
{                                          
        if(lcddev.id==0X9341||lcddev.id==0X6804||lcddev.id==0X5310||lcddev.id==0X1963)LCD_WR_REG(0X29);        //开启显示
        else if(lcddev.id==0X5510)LCD_WR_REG(0X2900);        //开启显示
        else LCD_WriteReg(0X07,0x0173);                                          //开启显示
}         
//LCD关闭显示
void LCD_DisplayOff(void)
{          
        if(lcddev.id==0X9341||lcddev.id==0X6804||lcddev.id==0X5310||lcddev.id==0X1963)LCD_WR_REG(0X28);        //关闭显示
        else if(lcddev.id==0X5510)LCD_WR_REG(0X2800);        //关闭显示
        else LCD_WriteReg(0X07,0x0);//关闭显示
}   
//设置光标位置
//Xpos:横坐标
//Ypos:纵坐标
void LCD_SetCursor(u16 Xpos, u16 Ypos)
{         
        if(lcddev.id==0X9341||lcddev.id==0X5310)
        {                    
                LCD_WR_REG(lcddev.setxcmd);
                LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);                          
                LCD_WR_REG(lcddev.setycmd);
                LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF);                
        }else if(lcddev.id==0X6804)
        {
                if(lcddev.dir==1)Xpos=lcddev.width-1-Xpos;//横屏时处理
                LCD_WR_REG(lcddev.setxcmd);
                LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);
                LCD_WR_REG(lcddev.setycmd);
                LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF);
        }else if(lcddev.id==0X1963)
        {                                          
                if(lcddev.dir==0)//x坐标需要变换
                {
                        Xpos=lcddev.width-1-Xpos;
                        LCD_WR_REG(lcddev.setxcmd);
                        LCD_WR_DATA(0);LCD_WR_DATA(0);                
                        LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);                          
                }else
                {
                        LCD_WR_REG(lcddev.setxcmd);
                        LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);                
                        LCD_WR_DATA((lcddev.width-1)>>8);LCD_WR_DATA((lcddev.width-1)&0XFF);                                                 
                }       
                LCD_WR_REG(lcddev.setycmd);
                LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF);                
                LCD_WR_DATA((lcddev.height-1)>>8);LCD_WR_DATA((lcddev.height-1)&0XFF);                                         
               
        }else if(lcddev.id==0X5510)
        {
                LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(Xpos>>8);                
                LCD_WR_REG(lcddev.setxcmd+1);LCD_WR_DATA(Xpos&0XFF);                         
                LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(Ypos>>8);                 
                LCD_WR_REG(lcddev.setycmd+1);LCD_WR_DATA(Ypos&0XFF);                       
        }else
        {
                if(lcddev.dir==1)Xpos=lcddev.width-1-Xpos;//横屏其实就是调转x,y坐标
                LCD_WriteReg(lcddev.setxcmd, Xpos);
                LCD_WriteReg(lcddev.setycmd, Ypos);
        }         
}                  
//设置LCD的自动扫描方向
//注意:其他函数可能会受到此函数设置的影响(尤其是9341/6804这两个奇葩),
//所以,一般设置为L2R_U2D即可,如果设置为其他扫描方式,可能导致显示不正常.
//dir:0~7,代表8个方向(具体定义见lcd.h)
//9320/9325/9328/4531/4535/1505/b505/5408/9341/5310/5510/1963等IC已经实际测试                     
void LCD_Scan_Dir(u8 dir)
{
        u16 regval=0;
        u16 dirreg=0;
        u16 temp;  
        if((lcddev.dir==1&&lcddev.id!=0X6804&&lcddev.id!=0X1963)||(lcddev.dir==0&&lcddev.id==0X1963))//横屏时,对6804和1963不改变扫描方向!竖屏时1963改变方向
        {                          
                switch(dir)//方向转换
                {
                        case 0:dir=6;break;
                        case 1:dir=7;break;
                        case 2:dir=4;break;
                        case 3:dir=5;break;
                        case 4:dir=1;break;
                        case 5:dir=0;break;
                        case 6:dir=3;break;
                        case 7:dir=2;break;             
                }
        }
        if(lcddev.id==0x9341||lcddev.id==0X6804||lcddev.id==0X5310||lcddev.id==0X5510||lcddev.id==0X1963)//9341/6804/5310/5510/1963,特殊处理
        {
                switch(dir)
                {
                        case L2R_U2D://从左到右,从上到下
                                regval|=(0<<7)|(0<<6)|(0<<5);
                                break;
                        case L2R_D2U://从左到右,从下到上
                                regval|=(1<<7)|(0<<6)|(0<<5);
                                break;
                        case R2L_U2D://从右到左,从上到下
                                regval|=(0<<7)|(1<<6)|(0<<5);
                                break;
                        case R2L_D2U://从右到左,从下到上
                                regval|=(1<<7)|(1<<6)|(0<<5);
                                break;         
                        case U2D_L2R://从上到下,从左到右
                                regval|=(0<<7)|(0<<6)|(1<<5);
                                break;
                        case U2D_R2L://从上到下,从右到左
                                regval|=(0<<7)|(1<<6)|(1<<5);
                                break;
                        case D2U_L2R://从下到上,从左到右
                                regval|=(1<<7)|(0<<6)|(1<<5);
                                break;
                        case D2U_R2L://从下到上,从右到左
                                regval|=(1<<7)|(1<<6)|(1<<5);
                                break;         
                }
                if(lcddev.id==0X5510)dirreg=0X3600;
                else dirreg=0X36;
                if((lcddev.id!=0X5310)&&(lcddev.id!=0X5510)&&(lcddev.id!=0X1963))regval|=0X08;//5310/5510/1963不需要BGR   
                if(lcddev.id==0X6804)regval|=0x02;//6804的BIT6和9341的反了          
                LCD_WriteReg(dirreg,regval);
                if(lcddev.id!=0X1963)//1963不做坐标处理
                {
                        if(regval&0X20)
                        {
                                if(lcddev.width<lcddev.height)//交换X,Y
                                {
                                        temp=lcddev.width;
                                        lcddev.width=lcddev.height;
                                        lcddev.height=temp;
                                }
                        }else  
                        {
                                if(lcddev.width>lcddev.height)//交换X,Y
                                {
                                        temp=lcddev.width;
                                        lcddev.width=lcddev.height;
                                        lcddev.height=temp;
                                }
                        }  
                }
                if(lcddev.id==0X5510)
                {
                        LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(0);
                        LCD_WR_REG(lcddev.setxcmd+1);LCD_WR_DATA(0);
                        LCD_WR_REG(lcddev.setxcmd+2);LCD_WR_DATA((lcddev.width-1)>>8);
                        LCD_WR_REG(lcddev.setxcmd+3);LCD_WR_DATA((lcddev.width-1)&0XFF);
                        LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(0);
                        LCD_WR_REG(lcddev.setycmd+1);LCD_WR_DATA(0);
                        LCD_WR_REG(lcddev.setycmd+2);LCD_WR_DATA((lcddev.height-1)>>8);
                        LCD_WR_REG(lcddev.setycmd+3);LCD_WR_DATA((lcddev.height-1)&0XFF);
                }else
                {
                        LCD_WR_REG(lcddev.setxcmd);
                        LCD_WR_DATA(0);LCD_WR_DATA(0);
                        LCD_WR_DATA((lcddev.width-1)>>8);LCD_WR_DATA((lcddev.width-1)&0XFF);
                        LCD_WR_REG(lcddev.setycmd);
                        LCD_WR_DATA(0);LCD_WR_DATA(0);
                        LCD_WR_DATA((lcddev.height-1)>>8);LCD_WR_DATA((lcddev.height-1)&0XFF);  
                }
          }else
        {
                switch(dir)
                {
                        case L2R_U2D://从左到右,从上到下
                                regval|=(1<<5)|(1<<4)|(0<<3);
                                break;
                        case L2R_D2U://从左到右,从下到上
                                regval|=(0<<5)|(1<<4)|(0<<3);
                                break;
                        case R2L_U2D://从右到左,从上到下
                                regval|=(1<<5)|(0<<4)|(0<<3);
                                break;
                        case R2L_D2U://从右到左,从下到上
                                regval|=(0<<5)|(0<<4)|(0<<3);
                                break;         
                        case U2D_L2R://从上到下,从左到右
                                regval|=(1<<5)|(1<<4)|(1<<3);
                                break;
                        case U2D_R2L://从上到下,从右到左
                                regval|=(1<<5)|(0<<4)|(1<<3);
                                break;
                        case D2U_L2R://从下到上,从左到右
                                regval|=(0<<5)|(1<<4)|(1<<3);
                                break;
                        case D2U_R2L://从下到上,从右到左
                                regval|=(0<<5)|(0<<4)|(1<<3);
                                break;         
                }
                dirreg=0X03;
                regval|=1<<12;
                LCD_WriteReg(dirreg,regval);
        }
}     
//画点
//x,y:坐标
//POINT_COLOR:此点的颜色
void LCD_DrawPoint(u16 x,u16 y)
{
        LCD_SetCursor(x,y);                //设置光标位置
        LCD_WriteRAM_Prepare();        //开始写入GRAM
        LCD_WR_DATA(POINT_COLOR);
}         
//快速画点
//x,y:坐标
//color:颜色
void LCD_Fast_DrawPoint(u16 x,u16 y,u16 color)
{          
        if(lcddev.id==0X9341||lcddev.id==0X5310)
        {
                LCD_WR_REG(lcddev.setxcmd);
                LCD_WR_DATA(x>>8);LCD_WR_DATA(x&0XFF);                           
                LCD_WR_REG(lcddev.setycmd);
                LCD_WR_DATA(y>>8);LCD_WR_DATA(y&0XFF);                           
        }else if(lcddev.id==0X5510)
        {
                LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(x>>8);  
                LCD_WR_REG(lcddev.setxcmd+1);LCD_WR_DATA(x&0XFF);          
                LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(y>>8);  
                LCD_WR_REG(lcddev.setycmd+1);LCD_WR_DATA(y&0XFF);
        }else if(lcddev.id==0X1963)
        {
                if(lcddev.dir==0)x=lcddev.width-1-x;
                LCD_WR_REG(lcddev.setxcmd);
                LCD_WR_DATA(x>>8);LCD_WR_DATA(x&0XFF);                
                LCD_WR_DATA(x>>8);LCD_WR_DATA(x&0XFF);                
                LCD_WR_REG(lcddev.setycmd);
                LCD_WR_DATA(y>>8);LCD_WR_DATA(y&0XFF);                
                LCD_WR_DATA(y>>8);LCD_WR_DATA(y&0XFF);                
        }else if(lcddev.id==0X6804)
        {                    
                if(lcddev.dir==1)x=lcddev.width-1-x;//横屏时处理
                LCD_WR_REG(lcddev.setxcmd);
                LCD_WR_DATA(x>>8);LCD_WR_DATA(x&0XFF);                         
                LCD_WR_REG(lcddev.setycmd);
                LCD_WR_DATA(y>>8);LCD_WR_DATA(y&0XFF);                
        }else
        {
                if(lcddev.dir==1)x=lcddev.width-1-x;//横屏其实就是调转x,y坐标
                LCD_WriteReg(lcddev.setxcmd,x);
                LCD_WriteReg(lcddev.setycmd,y);
        }       
        LCD_RS_CLR;
        LCD_CS_CLR;
        DATAOUT(lcddev.wramcmd);//写指令  
        LCD_WR_CLR;
        LCD_WR_SET;
        LCD_CS_SET;
        LCD_WR_DATA(color);                //写数据
}
//SSD1963 背光设置
//pwm:背光等级,0~100.越大越亮.
void LCD_SSD_BackLightSet(u8 pwm)
{       
        LCD_WR_REG(0xBE);        //配置PWM输出
        LCD_WR_DATA(0x05);        //1设置PWM频率
        LCD_WR_DATA(pwm*2.55);//2设置PWM占空比
        LCD_WR_DATA(0x01);        //3设置C
        LCD_WR_DATA(0xFF);        //4设置D
        LCD_WR_DATA(0x00);        //5设置E
        LCD_WR_DATA(0x00);        //6设置F
}
//设置LCD显示方向
//dir:0,竖屏;1,横屏
void LCD_Display_Dir(u8 dir)
{
        if(dir==0)                        //竖屏
        {
                lcddev.dir=0;        //竖屏
                lcddev.width=240;
                lcddev.height=320;
                if(lcddev.id==0X9341||lcddev.id==0X6804||lcddev.id==0X5310)
                {
                        lcddev.wramcmd=0X2C;
                         lcddev.setxcmd=0X2A;
                        lcddev.setycmd=0X2B;           
                        if(lcddev.id==0X6804||lcddev.id==0X5310)
                        {
                                lcddev.width=320;
                                lcddev.height=480;
                        }
                }else if(lcddev.id==0x5510)
                {
                        lcddev.wramcmd=0X2C00;
                         lcddev.setxcmd=0X2A00;
                        lcddev.setycmd=0X2B00;
                        lcddev.width=480;
                        lcddev.height=800;
                }else if(lcddev.id==0X1963)
                {
                        lcddev.wramcmd=0X2C;        //设置写入GRAM的指令
                        lcddev.setxcmd=0X2B;        //设置写X坐标指令
                        lcddev.setycmd=0X2A;        //设置写Y坐标指令
                        lcddev.width=480;                //设置宽度480
                        lcddev.height=800;                //设置高度800  
                }else
                {
                        lcddev.wramcmd=0X22;
                         lcddev.setxcmd=0X20;
                        lcddev.setycmd=0X21;  
                }
        }else                                 //横屏
        {                                         
                lcddev.dir=1;        //横屏
                lcddev.width=320;
                lcddev.height=240;
                if(lcddev.id==0X9341||lcddev.id==0X5310)
                {
                        lcddev.wramcmd=0X2C;
                         lcddev.setxcmd=0X2A;
                        lcddev.setycmd=0X2B;           
                }else if(lcddev.id==0X6804)         
                {
                        lcddev.wramcmd=0X2C;
                         lcddev.setxcmd=0X2B;
                        lcddev.setycmd=0X2A;
                }else if(lcddev.id==0x5510)
                {
                        lcddev.wramcmd=0X2C00;
                         lcddev.setxcmd=0X2A00;
                        lcddev.setycmd=0X2B00;
                        lcddev.width=800;
                        lcddev.height=480;
                }else if(lcddev.id==0X1963)
                {
                        lcddev.wramcmd=0X2C;        //设置写入GRAM的指令
                        lcddev.setxcmd=0X2A;        //设置写X坐标指令
                        lcddev.setycmd=0X2B;        //设置写Y坐标指令
                        lcddev.width=800;                //设置宽度800
                        lcddev.height=480;                //设置高度480  
                }else
                {
                        lcddev.wramcmd=0X22;
                         lcddev.setxcmd=0X21;
                        lcddev.setycmd=0X20;  
                }
                if(lcddev.id==0X6804||lcddev.id==0X5310)
                {          
                        lcddev.width=480;
                        lcddev.height=320;                        
                }
        }
        LCD_Scan_Dir(DFT_SCAN_DIR);        //默认扫描方向
}         
//设置窗口,并自动设置画点坐标到窗口左上角(sx,sy).
//sx,sy:窗口起始坐标(左上角)
//width,height:窗口宽度和高度,必须大于0!!
//窗体大小:width*height.
void LCD_Set_Window(u16 sx,u16 sy,u16 width,u16 height)
{   
        u8 hsareg,heareg,vsareg,veareg;
        u16 hsaval,heaval,vsaval,veaval;
        u16 twidth,theight;
        twidth=sx+width-1;
        theight=sy+height-1;
        if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X6804||(lcddev.dir==1&&lcddev.id==0X1963))
        {
                LCD_WR_REG(lcddev.setxcmd);
                LCD_WR_DATA(sx>>8);
                LCD_WR_DATA(sx&0XFF);         
                LCD_WR_DATA(twidth>>8);
                LCD_WR_DATA(twidth&0XFF);  
                LCD_WR_REG(lcddev.setycmd);
                LCD_WR_DATA(sy>>8);
                LCD_WR_DATA(sy&0XFF);
                LCD_WR_DATA(theight>>8);
                LCD_WR_DATA(theight&0XFF);
        }else if(lcddev.id==0X1963)//1963竖屏特殊处理
        {
                sx=lcddev.width-width-sx;
                height=sy+height-1;
                LCD_WR_REG(lcddev.setxcmd);
                LCD_WR_DATA(sx>>8);
                LCD_WR_DATA(sx&0XFF);         
                LCD_WR_DATA((sx+width-1)>>8);
                LCD_WR_DATA((sx+width-1)&0XFF);  
                LCD_WR_REG(lcddev.setycmd);
                LCD_WR_DATA(sy>>8);
                LCD_WR_DATA(sy&0XFF);
                LCD_WR_DATA(height>>8);
                LCD_WR_DATA(height&0XFF);                
        }else if(lcddev.id==0X5510)
        {
                LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(sx>>8);  
                LCD_WR_REG(lcddev.setxcmd+1);LCD_WR_DATA(sx&0XFF);          
                LCD_WR_REG(lcddev.setxcmd+2);LCD_WR_DATA(twidth>>8);   
                LCD_WR_REG(lcddev.setxcmd+3);LCD_WR_DATA(twidth&0XFF);   
                LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(sy>>8);   
                LCD_WR_REG(lcddev.setycmd+1);LCD_WR_DATA(sy&0XFF);  
                LCD_WR_REG(lcddev.setycmd+2);LCD_WR_DATA(theight>>8);   
                LCD_WR_REG(lcddev.setycmd+3);LCD_WR_DATA(theight&0XFF);  
        }else        //其他驱动IC
        {
                if(lcddev.dir==1)//横屏
                {
                        //窗口值
                        hsaval=sy;                               
                        heaval=theight;
                        vsaval=lcddev.width-twidth-1;
                        veaval=lcddev.width-sx-1;                               
                }else
                {
                        hsaval=sx;                               
                        heaval=twidth;
                        vsaval=sy;
                        veaval=theight;
                }
                hsareg=0X50;heareg=0X51;//水平方向窗口寄存器
                vsareg=0X52;veareg=0X53;//垂直方向窗口寄存器                                                                     
                //设置寄存器值
                LCD_WriteReg(hsareg,hsaval);
                LCD_WriteReg(heareg,heaval);
                LCD_WriteReg(vsareg,vsaval);
                LCD_WriteReg(veareg,veaval);               
                LCD_SetCursor(sx,sy);        //设置光标位置
        }
}
//初始化lcd
//该初始化函数可以初始化各种ALIENTEK出品的LCD液晶屏
//本函数占用较大flash,用户可以根据自己的实际情况,删掉未用到的LCD初始化代码.以节省空间.
void LCD_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE); //使能PORTB,C时钟和AFIO时钟
        GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);//开启SWD,失能JTAG
       
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_9|GPIO_Pin_8|GPIO_Pin_7|GPIO_Pin_6;           ///PORTC6~10复用推挽输出
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOC, &GPIO_InitStructure); //GPIOC       

        GPIO_SetBits(GPIOC,GPIO_Pin_10|GPIO_Pin_9|GPIO_Pin_8|GPIO_Pin_7|GPIO_Pin_6);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;        //  PORTB推挽输出
        GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB

        GPIO_SetBits(GPIOB,GPIO_Pin_All);

delay_ms(50); // delay 50 ms
        LCD_WriteReg(0x0000,0x0001);
        delay_ms(50); // delay 50 ms
          lcddev.id = LCD_ReadReg(0x0000);   
        if(lcddev.id<0XFF||lcddev.id==0XFFFF||lcddev.id==0X9300)//读到ID不正确,新增lcddev.id==0X9300判断,因为9341在未被复位的情况下会被读成9300
        {       
                //尝试9341 ID的读取               
                LCD_WR_REG(0XD3);                                  
                LCD_RD_DATA();                                 //dummy read        
                LCD_RD_DATA();                       //读到0X00
                  lcddev.id=LCD_RD_DATA();           //读取93                                                                  
                lcddev.id<<=8;
                lcddev.id|=LCD_RD_DATA();          //读取41                                      
        }
        printf(" LCD ID:%x\r\n",lcddev.id); //打印LCD ID  
        if(lcddev.id==0X9341)        //9341初始化
        {         
                LCD_WR_REG(0xCF);  
                LCD_WR_DATAX(0x00);
                LCD_WR_DATAX(0xC1);
                LCD_WR_DATAX(0X30);
                LCD_WR_REG(0xED);  
                LCD_WR_DATAX(0x64);
                LCD_WR_DATAX(0x03);
                LCD_WR_DATAX(0X12);
                LCD_WR_DATAX(0X81);
                LCD_WR_REG(0xE8);  
                LCD_WR_DATAX(0x85);
                LCD_WR_DATAX(0x10);
                LCD_WR_DATAX(0x7A);
                LCD_WR_REG(0xCB);  
                LCD_WR_DATAX(0x39);
                LCD_WR_DATAX(0x2C);
                LCD_WR_DATAX(0x00);
                LCD_WR_DATAX(0x34);
                LCD_WR_DATAX(0x02);
                LCD_WR_REG(0xF7);  
                LCD_WR_DATAX(0x20);
                LCD_WR_REG(0xEA);  
                LCD_WR_DATAX(0x00);
                LCD_WR_DATAX(0x00);
                LCD_WR_REG(0xC0);    //Power control
                LCD_WR_DATAX(0x1B);   //VRH[5:0]
                LCD_WR_REG(0xC1);    //Power control
                LCD_WR_DATAX(0x01);   //SAP[2:0];BT[3:0]
                LCD_WR_REG(0xC5);    //VCM control
                LCD_WR_DATAX(0x30);          //3F
                LCD_WR_DATAX(0x30);          //3C
                LCD_WR_REG(0xC7);    //VCM control2
                LCD_WR_DATAX(0XB7);
                LCD_WR_REG(0x36);    // Memory Access Control
                LCD_WR_DATAX(0x48);
                LCD_WR_REG(0x3A);   
                LCD_WR_DATAX(0x55);
                LCD_WR_REG(0xB1);   
                LCD_WR_DATAX(0x00);   
                LCD_WR_DATAX(0x1A);
                LCD_WR_REG(0xB6);    // Display Function Control
                LCD_WR_DATAX(0x0A);
                LCD_WR_DATAX(0xA2);
                LCD_WR_REG(0xF2);    // 3Gamma Function Disable
                LCD_WR_DATAX(0x00);
                LCD_WR_REG(0x26);    //Gamma curve selected
                LCD_WR_DATAX(0x01);
                LCD_WR_REG(0xE0);    //Set Gamma
                LCD_WR_DATAX(0x0F);
                LCD_WR_DATAX(0x2A);
                LCD_WR_DATAX(0x28);
                LCD_WR_DATAX(0x08);
                LCD_WR_DATAX(0x0E);
                LCD_WR_DATAX(0x08);
                LCD_WR_DATAX(0x54);
                LCD_WR_DATAX(0XA9);
                LCD_WR_DATAX(0x43);
                LCD_WR_DATAX(0x0A);
                LCD_WR_DATAX(0x0F);
                LCD_WR_DATAX(0x00);
                LCD_WR_DATAX(0x00);
                LCD_WR_DATAX(0x00);
                LCD_WR_DATAX(0x00);                  
                LCD_WR_REG(0XE1);    //Set Gamma
                LCD_WR_DATAX(0x00);
                LCD_WR_DATAX(0x15);
                LCD_WR_DATAX(0x17);
                LCD_WR_DATAX(0x07);
                LCD_WR_DATAX(0x11);
                LCD_WR_DATAX(0x06);
                LCD_WR_DATAX(0x2B);
                LCD_WR_DATAX(0x56);
                LCD_WR_DATAX(0x3C);
                LCD_WR_DATAX(0x05);
                LCD_WR_DATAX(0x10);
                LCD_WR_DATAX(0x0F);
                LCD_WR_DATAX(0x3F);
                LCD_WR_DATAX(0x3F);
                LCD_WR_DATAX(0x0F);
                LCD_WR_REG(0x2B);
                LCD_WR_DATAX(0x00);
                LCD_WR_DATAX(0x00);
                LCD_WR_DATAX(0x01);
                LCD_WR_DATAX(0x3f);
                LCD_WR_REG(0x2A);
                LCD_WR_DATAX(0x00);
                LCD_WR_DATAX(0x00);
                LCD_WR_DATAX(0x00);
                LCD_WR_DATAX(0xef);         
                LCD_WR_REG(0x11); //Exit Sleep
                delay_ms(120);
                LCD_WR_REG(0x29); //display on       
        }
       
        LCD_Display_Dir(1);                         //默认为竖屏
        LCD_LED=1;                                        //点亮背光
        LCD_Clear(WHITE);
}                    
  
//清屏函数
//color:要清屏的填充色
void LCD_Clear(u16 color)
{
        u32 index=0;      
        u32 totalpoint=lcddev.width;
        totalpoint*=lcddev.height;                         //得到总点数
        if((lcddev.id==0X6804)&&(lcddev.dir==1))//6804横屏的时候特殊处理  
        {                                                    
                lcddev.dir=0;         
                lcddev.setxcmd=0X2A;
                lcddev.setycmd=0X2B;                                  
                LCD_SetCursor(0x00,0x0000);                //设置光标位置  
                lcddev.dir=1;         
                  lcddev.setxcmd=0X2B;
                lcddev.setycmd=0X2A;           
        }else LCD_SetCursor(0x00,0x0000);        //设置光标位置
        LCD_WriteRAM_Prepare();                     //开始写入GRAM                    
        for(index=0;index<totalpoint;index++)LCD_WR_DATA(color);       
}  
//在指定区域内填充指定颜色
//区域大小:(xend-xsta+1)*(yend-ysta+1)
//xsta
//color:要填充的颜色
void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color)
{         
        u16 i,j;
        u16 xlen=0;
        u16 temp;
        if((lcddev.id==0X6804)&&(lcddev.dir==1))        //6804横屏的时候特殊处理  
        {
                temp=sx;
                sx=sy;
                sy=lcddev.width-ex-1;          
                ex=ey;
                ey=lcddev.width-temp-1;
                lcddev.dir=0;         
                lcddev.setxcmd=0X2A;
                lcddev.setycmd=0X2B;                                  
                LCD_Fill(sx,sy,ex,ey,color);  
                lcddev.dir=1;         
                  lcddev.setxcmd=0X2B;
                lcddev.setycmd=0X2A;           
        }else
        {
                xlen=ex-sx+1;         
                for(i=sy;i<=ey;i++)
                {
                         LCD_SetCursor(sx,i);                                      //设置光标位置
                        LCD_WriteRAM_Prepare();                             //开始写入GRAM          
                        for(j=0;j<xlen;j++)LCD_WR_DATA(color);        //设置光标位置             
                }
        }
}  
//在指定区域内填充指定颜色块                         
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)   
//color:要填充的颜色
void LCD_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color)
{  
        u16 height,width;
        u16 i,j;
        width=ex-sx+1;                         //得到填充的宽度
        height=ey-sy+1;                        //高度
        for(i=0;i<height;i++)
        {
                LCD_SetCursor(sx,sy+i);           //设置光标位置
                LCD_WriteRAM_Prepare();     //开始写入GRAM
                for(j=0;j<width;j++)LCD_WR_DATA(color[i*width+j]);//写入数据
        }          
}
//画线
//x1,y1:起点坐标
//x2,y2:终点坐标  
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2)
{
        u16 t;
        int xerr=0,yerr=0,delta_x,delta_y,distance;
        int incx,incy,uRow,uCol;
        delta_x=x2-x1; //计算坐标增量
        delta_y=y2-y1;
        uRow=x1;
        uCol=y1;
        if(delta_x>0)incx=1; //设置单步方向
        else if(delta_x==0)incx=0;//垂直线
        else {incx=-1;delta_x=-delta_x;}
        if(delta_y>0)incy=1;
        else if(delta_y==0)incy=0;//水平线
        else{incy=-1;delta_y=-delta_y;}
        if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴
        else distance=delta_y;
        for(t=0;t<=distance+1;t++ )//画线输出
        {  
                LCD_DrawPoint(uRow,uCol);//画点
                xerr+=delta_x ;
                yerr+=delta_y ;
                if(xerr>distance)
                {
                        xerr-=distance;
                        uRow+=incx;
                }
                if(yerr>distance)
                {
                        yerr-=distance;
                        uCol+=incy;
                }
        }  
}   
//画矩形          
//(x1,y1),(x2,y2):矩形的对角坐标
void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2)
{
        LCD_DrawLine(x1,y1,x2,y1);
        LCD_DrawLine(x1,y1,x1,y2);
        LCD_DrawLine(x1,y2,x2,y2);
        LCD_DrawLine(x2,y1,x2,y2);
}
//在指定位置画一个指定大小的圆
//(x,y):中心点
//r    :半径
void LCD_Draw_Circle(u16 x0,u16 y0,u8 r)
{
        int a,b;
        int di;
        a=0;b=r;          
        di=3-(r<<1);             //判断下个点位置的标志
        while(a<=b)
        {
                LCD_DrawPoint(x0+a,y0-b);             //5
                LCD_DrawPoint(x0+b,y0-a);             //0           
                LCD_DrawPoint(x0+b,y0+a);             //4               
                LCD_DrawPoint(x0+a,y0+b);             //6
                LCD_DrawPoint(x0-a,y0+b);             //1      
                LCD_DrawPoint(x0-b,y0+a);            
                LCD_DrawPoint(x0-a,y0-b);             //2            
                  LCD_DrawPoint(x0-b,y0-a);             //7                     
                a++;
                //使用Bresenham算法画圆     
                if(di<0)di +=4*a+6;          
                else
                {
                        di+=10+4*(a-b);   
                        b--;
                }                                                     
        }
}                                                                           
//在指定位置显示一个字符
//x,y:起始坐标
//num:要显示的字符:" "--->"~"
//size:字体大小 12/16/24
//mode:叠加方式(1)还是非叠加方式(0)
void LCD_ShowChar(u16 x,u16 y,u8 num,u8 size,u8 mode)
{                                                            
    u8 temp,t1,t;
        u16 y0=y;
        u8 csize=(size/8+((size%8)?1:0))*(size/2);                //得到字体一个字符对应点阵集所占的字节数       
        num=num-' ';//得到偏移后的值(ASCII字库是从空格开始取模,所以-' '就是对应字符的字库)
        for(t=0;t<csize;t++)
        {   
                if(size==12)temp=asc2_1206[num][t];                  //调用1206字体
                else if(size==16)temp=asc2_1608[num][t];        //调用1608字体
                else if(size==24)temp=asc2_2412[num][t];        //调用2412字体
                else return;                                                                //没有的字库
                for(t1=0;t1<8;t1++)
                {                            
                        if(temp&0x80)LCD_Fast_DrawPoint(x,y,POINT_COLOR);
                        else if(mode==0)LCD_Fast_DrawPoint(x,y,BACK_COLOR);
                        temp<<=1;
                        y++;
                        if(y>=lcddev.height)return;                //超区域了
                        if((y-y0)==size)
                        {
                                y=y0;
                                x++;
                                if(x>=lcddev.width)return;        //超区域了
                                break;
                        }
                }           
        }                                            
}   
//m^n函数
//返回值:m^n次方.
u32 LCD_Pow(u8 m,u8 n)
{
        u32 result=1;         
        while(n--)result*=m;   
        return result;
}                         
//显示数字,高位为0,则不显示
//x,y :起点坐标         
//len :数字的位数
//size:字体大小
//color:颜色
//num:数值(0~4294967295);         
void LCD_ShowNum(u16 x,u16 y,u32 num,u8 len,u8 size)
{                
        u8 t,temp;
        u8 enshow=0;                                                  
        for(t=0;t<len;t++)
        {
                temp=(num/LCD_Pow(10,len-t-1))%10;
                if(enshow==0&&t<(len-1))
                {
                        if(temp==0)
                        {
                                LCD_ShowChar(x+(size/2)*t,y,' ',size,0);
                                continue;
                        }else enshow=1;
                          
                }
                 LCD_ShowChar(x+(size/2)*t,y,temp+'0',size,0);
        }
}
//显示数字,高位为0,还是显示
//x,y:起点坐标
//num:数值(0~999999999);         
//len:长度(即要显示的位数)
//size:字体大小
//mode:
//[7]:0,不填充;1,填充0.
//[6:1]:保留
//[0]:0,非叠加显示;1,叠加显示.
void LCD_ShowxNum(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode)
{  
        u8 t,temp;
        u8 enshow=0;                                                  
        for(t=0;t<len;t++)
        {
                temp=(num/LCD_Pow(10,len-t-1))%10;
                if(enshow==0&&t<(len-1))
                {
                        if(temp==0)
                        {
                                if(mode&0X80)LCD_ShowChar(x+(size/2)*t,y,'0',size,mode&0X01);  
                                else LCD_ShowChar(x+(size/2)*t,y,' ',size,mode&0X01);  
                                continue;
                        }else enshow=1;
                          
                }
                 LCD_ShowChar(x+(size/2)*t,y,temp+'0',size,mode&0X01);
        }
}
//显示字符串
//x,y:起点坐标
//width,height:区域大小  
//size:字体大小
//*p:字符串起始地址                  
void LCD_ShowString(u16 x,u16 y,u16 width,u16 height,u8 size,u8 *p)
{         
        u8 x0=x;
        width+=x;
        height+=y;
    while((*p<='~')&&(*p>=' '))//判断是不是非法字符!
    {      
        if(x>=width){x=x0;y+=size;}
        if(y>=height)break;//退出
        LCD_ShowChar(x,y,*p,size,0);
        x+=size/2;
        p++;
    }  
}

使用特权

评论回复
15
wangjiahao88|  楼主 | 2018-11-2 13:59 | 只看该作者
程序代码

压缩包 如下


电波钟.zip

3.2 MB

使用特权

评论回复
16
chongdongchen| | 2018-11-4 09:25 | 只看该作者
wangjiahao88 发表于 2018-11-2 13:32
为什么不能上传图片了?

赶紧拿出多年前买的,和你的差不多一样。当时觉得挺好玩,后来由于信号太差放弃了。要放在窗口边才接收到信号,房间里面波形全乱。
想着反正家里都有WiFi,就做了一个WiFi时钟,到现在一直用着,比这个完美多了。



使用特权

评论回复
17
戈卫东| | 2018-11-4 11:44 | 只看该作者
非常容易被干扰。
你这连着USB的根本不可能收到信号。
。。。。。。

使用特权

评论回复
18
wangjiahao88|  楼主 | 2018-11-4 12:11 | 只看该作者
哦?是吗?收不到信号?

使用特权

评论回复
19
wangjiahao88|  楼主 | 2018-11-4 12:12 | 只看该作者
我买了一个 卡西欧电波表,看到只有L3信号强度的时候,才会收信成功

使用特权

评论回复
20
heimaojingzhang| | 2018-11-6 13:03 | 只看该作者
请问BPC电波是什么呀

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

462

主题

7478

帖子

29

粉丝