vfd折腾(二)
这篇是前期程序部分,主要讲驱动pt6311的程序
电路见上一篇博文
1 #ifndef PT6311_H 2 #define PT6311_H 3 4 #include "sys.h" 5 #include "delay.h" 6 extern u8 dspbuf[30],dspseg[13]; 7 extern const u8 ADDR[30]; //addr 8 extern const u16 font[37]; //font 9 10 #define GPS 0x08 11 #define ALARM 0x10 12 #define ALL 0x20 13 #define CONT 0x40 14 #define LP 0x80 15 16 #define COLON 0x80 //personal protocal 17 #define CLR 36 18 #define DI PCout(2) 19 #define DO PCin(3) 20 #define CLK PCout(0) 21 #define STB PCout(13) 22 23 void InitIo_PT6311(void); 24 void Init_PT6311(void); 25 void OpenStrobe_PT6311(void); 26 void WriteByte_PT6311(u8 dat); 27 u8 ReadByte_PT6311(void); 28 void TransCoding(void);//transcoding 29 unsigned int Pow2(u8 y); 30 #define CMD_ModeSetting 0x00 31 #define CMD_DataSetting 0x40 32 #define CMD_AddressSetting 0xc0 33 #define CMD_DisplaySetting 0x80 34 35 #endif
//定义io以及声明一些实现函数
1 #include "pt6311.h" 2 #include "stdio.h" 3 //auth:katachi 4 //time:2017-12-30 5 //func:driver for pt6311 6 const u8 ADDR[]={0x00,0x01,//digit 1 7 0x03,0x04,//digit 2 8 0x06,0x07,//digit 3 9 0x09,0x0a,//digit 4 10 0x0c,0x0d,//digit 5 11 0x0f,0x10,//digit 6 12 0x12,0x13,//digit 7 13 0x15,0x16,//digit 8 14 0x18,0x19,//digit 9 15 0x1B,0x1C,//digit 10 16 0x1E,0x1F,//digit 11 17 0x21,0x22,//digit 12 18 0x24,0x25,//digit 13 19 0x27,0x28,//digit 14 20 0x2a,0x2b};//digit 15 21 const u16 font[37]={ 22 0x7266,0x2040,0x6186,0x61c2,0x23c0,0x43c2,0x43c6,0x5020,0x63c6,0x63c2,//0-9 23 0x30e0,0x68d2,0x4206,0x6852,0x4386,0x4384,0x42ce,0x23c4,0x4812,0x2048, 24 0x130c,0x206,0x3644,0x264c,0x6246,0x6384,0x624e,0x638c,0x43c2,0x4810, 25 0x2246,0x1224,0x226c,0x1428,0x1410,0x5022,//a-z 26 0};//: 27 u8 dspbuf[30],dspseg[13]; 28 unsigned int Pow2(u8 y) 29 { 30 u16 x=1; 31 if (y) 32 { 33 while (y--) 34 x*=2; 35 } 36 else 37 x=1; 38 return x; 39 } 40 void TransCoding(void)//recongnize num or char or with colon and transcoding the dspseg to pt6311 ram 41 { 42 u8 i,j;u16 tmp;
//2018年1月14日22点44分已修改
for (i=0;i<30;i++)dspbuf[i]=0;
//起初只运行了一次这个函数,没发现这个bug 因为用的全是或运算,如某位上次为1那么一直为1
//加这句清零
43 for (i=0;i<13;i++)//seg==i 44 { 45 if (i==0) //for segment 0 display temp lvl 46 { 47 tmp=Pow2(dspseg[0]) - 1; 48 tmp<<=4; 49 } 50 else if (i==12)//for ui 51 { 52 //dspseg[12] 8bit 53 // _ _ _ _ , _ _ _ _ 54 // LOWPOWER CONTINUPAUSE ALL ALARM GPS WEEK 55 j=dspseg[12]; 56 57 if (j&0x08)//GPS 58 tmp=0x80; //= 59 if (j&0x10)//ALARM 60 tmp|=0x20; //|= 61 if (j&0x20)//ALL 62 tmp|=0x300; 63 if (j&0x40)//CT 64 tmp|=0xc00; 65 if (j&0x80)//LP 66 tmp|=0x7000; 67 j&=0x07;//get week 68 j--; 69 if (j>4)//sat sun 70 tmp|=j+1; 71 else //mon to fri 72 tmp|=1<<j; 73 } 74 else 75 { 76 //tmp=font['p'-87+i];//ascii to personal font 77 if (dspseg[i]>0x80)//num with colon 78 { 79 dspseg[i]-=0x80; 80 tmp=font[dspseg[i]]+1; 81 } 82 else if (dspseg[i]>90 && dspseg[i]<0x80)//charac 83 tmp=font[dspseg[i]-87]; 84 else 85 tmp=font[dspseg[i]];//plain num 86 } 87 //transcoding 88 if(i<8) 89 { 90 for (j=0;j<15;j++) 91 { 92 dspbuf[2*j]|=(tmp&0x1)<<i; 93 tmp>>=1; 94 } 95 } 96 else 97 { 98 for (j=1;j<16;j++) 99 { 100 dspbuf[2*j-1]|=(tmp&0x1)<<(i-8); 101 tmp>>=1; 102 } 103 } 104 } 105 } 106 void OpenStrobe_PT6311(void) 107 { 108 STB=1; 109 delay_us(1); 110 STB=0; 111 } 112 void InitIo_PT6311() 113 { 114 GPIO_InitTypeDef GPIO_InitStructure; 115 116 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //enable portc 117 118 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_2|GPIO_Pin_13; 119 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //ppout 120 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 121 GPIO_Init(GPIOC, &GPIO_InitStructure); 122 123 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; 124 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 125 GPIO_Init(GPIOC, &GPIO_InitStructure); 126 } 127 void Init_PT6311(void) 128 { 129 u8 i; 130 131 InitIo_PT6311(); 132 133 OpenStrobe_PT6311(); 134 WriteByte_PT6311(CMD_ModeSetting|0x0e);//15digits 13sg 135 136 OpenStrobe_PT6311(); 137 WriteByte_PT6311(CMD_DataSetting|0x04); //fixed addr 138 139 for (i=0;i<30;i++) 140 { 141 OpenStrobe_PT6311(); 142 WriteByte_PT6311(CMD_AddressSetting|ADDR[i]); 143 WriteByte_PT6311(0xff); 144 } 145 146 OpenStrobe_PT6311(); 147 WriteByte_PT6311(CMD_DisplaySetting|0x0f);//on 14/16 148 } 149 void WriteByte_PT6311(u8 dat) 150 { 151 u8 i; 152 153 CLK=1;//de-pulldown 154 for (i=0;i<8;i++) 155 { 156 CLK=0; //>>200ns 157 DI=dat&0x01; //send a bit to pt6311's data in pin 158 dat>>=1; //lsb first 159 CLK=1; 160 } 161 } 162 u8 ReadByte_PT6311(void) 163 { 164 u8 dat,i; 165 CLK=1; 166 delay_us(1); 167 for (i=0;i<8;i++) 168 { 169 CLK=0; 170 dat>>=1; //lsb first 171 if (DO) 172 dat|=0x80; //catch a bit from pt6311's data out pin 173 CLK=1; 174 } 175 return dat; 176 }
//依次讲解:
ADDR数组:存放了上一篇博文描述的15digit13segment对应ram的地址

我从网上找到的只有pt6312的驱动,他们几乎都用的地址自增模式,
因为本事似乎pt6312的地址就恰好连续的,

如图可知,如果段以及位合适,那么就可以使用地址自增模式。
地址自增:
话说这个datasheet我可能前前后后看了有十来遍(+_+)?
不知到是不是理解的问题,反正我的理解就是如果按照我那个需求,用地址自增有几个字节就无效了
我的实现是固定地址,依次给需要的地址写入内容,故定义了这个数组
下面的font字库是我自己根据相应的位段写好的码,这中间走了弯路,上一篇博文也提到了。
是这样,我抄位段的时候是反着vfd抄的,而我推也按照他来推了,最后显示,完了 上下颠倒了。
咋整???为什么不讲究就这样了?我想用左边的横条显示温度,他满的时候刚好最上面是橙色的,颠倒过来不爽!!
后期也想使用那些图标,总之就是强迫症。当时推这些玩意儿估计用了四十分钟,我用的16位来存的,因为它的位段我几乎都用了。
然后就比对上下,发现似乎不能直接交换bit15到bit0这样。咋整??
硬来!!!
#include "stdio.h" int main() { unsigned int font[36]={0x7266,0x204,0x630c,0x4836,0x3c4,0x6186,0x6c32,0x1022,0x63c6,0x43c6,//0-9 0x1324,0x4b16,0x6042,0x4a16,0x61c2,0x21c2,0x6742,0x23c4,0x4812,0x604,//a-j 0xc30,0x6040,0x206c,0x264c,0x6246,0x21c6,0x6646,0x25c6,0x6186,0x812,//k-t 0x6244,0x3060,0x3664,0x1428,0x828,0x5022}; unsigned char i,j; unsigned int ta,tb; for (i=0;i<36;i++) { ta=font[i];tb=0; //clr tb|=(ta&0x01)<<15;ta>>=1; tb|=(ta&0x01)<<14;ta>>=1; tb|=(ta&0x01)<<13;ta>>=1; tb|=(ta&0x01)<<10;ta>>=1; tb|=(ta&0x01)<<11;ta>>=1; tb|=(ta&0x01)<<12;ta>>=1; tb|=(ta&0x01)<<9;ta>>=1; tb|=(ta&0x01)<<8;ta>>=1; tb|=(ta&0x01)<<7;ta>>=1; tb|=(ta&0x01)<<6;ta>>=1; tb|=(ta&0x01)<<3;ta>>=1; tb|=(ta&0x01)<<4;ta>>=1; tb|=(ta&0x01)<<5;ta>>=1; tb|=(ta&0x01)<<2;ta>>=1; tb|=(ta&0x01)<<1;ta>>=1; tb|=(ta&0x01); printf("%#x,",tb); } printf("%d %d",'a','b'); return 0; }
我又简单的根据位的分布强行把bit交换,这下好了终于ok了😀
dspbuf是那要写入的30个8bit字节,dspseg是vfd的每一位对应显示的内容
pow2是求2的指数幂函数
transcoding是将dspseg的内容转换为要写入的字节,这个函数应该是最复杂的了,当时也是想的比较久的。
程序一进去是判断dspseg的位因为0和12特殊。
0是横线段,根据规律我用pow2刚好实现输入数字多少就对应显示几条横线。
12是各个图标,我定义它低三位来存放星期,对应的图标就是右边那5个。星期六星期天怎么办??暂时用的二进制解决😂😂
剩下的每一bit相当于当寄存器来用,具体看程序注释,应该很清楚了。
1-11部分就是判断是显示数字还是字符,
这里利用的是数字字面值和字母的ascii码中间又较大的差值来实现,ascii码的值比较大,小的话肯定就是数字了。
数字里面又有个判断是否带colon,因为又几个位后面是带冒号的,这里又用到了ascii码没用到8bit的MSB,所以我定义了0x80位带colon的标志,
而vfd的colon又刚好只是最低位(断码标号为0),所以满足条件加一就行了。
剩下的就是字母了,87是他们之间的差值(综合了ascii存进去那个值,以及字母再font里面的位置偏移)。
再剩下的程序就是最麻烦的地方了!!!!
看过pt6311的datasheet就知道,它tm显示的时候,刷进去一个字节显示的确是不同为的同一段!!!
就是比如我从头给他写个0xff 那么他只是将seg0-seg7的dig1置高,最后的结果就是那几位的那一段亮了,
而我字库存的是某个字符的全部断码,这里又废了一番功夫!别看那么短几行,当时不知道脑袋咋了,反正想了挺久。
2019年4月22日13:14:33修正:
原图中(见上一贴)将seg和grid对换了位置,本来每个grid之间的seg就是并行的,对调后:
给grid赋值,即欲选中某位数码管却选中了不同位的同一段,
给seg赋值,欲选中某段数码管却选中了某一位数码管。
最终出现上述描述的显示不同位的同一段。多加的那部分程序只是再做一遍串并转换!
依次取dspseg的bit再存到dspbuf对应的bit,又有低8bit和高8bit之分,具体看程序
再剩下的就是基本io的操作了,按照时序来的。
stb相当于使能端,低有效。每个新的操作之前都要给他来个下降沿,
告诉pt6311我要有新动作了,不然他以为你只是更改上次操作地址的内容。(这一点我也迷糊了很久,起先程序搭好了,发进去,毛都没有!)
剩下就没什么了😀
到此操作这个芯片的底层程序就搞定了,还封装了几个api,假如实际应用的时候不需要一次把每个seg都刷的话,可以更改那个transcoding函数,
比如显示时间的时候,没必要刷秒的时候每次去刷小时啥的,反正怎么需要怎么改
最后附主函数,用串口调试这玩意
1 #include "led.h" 2 #include "delay.h" 3 #include "sys.h" 4 #include "usart.h" 5 #include "pt6311.h" 6 #include "string.h" 7 8 int main(void) 9 { 10 u8 t,i; 11 u8 len; 12 13 delay_init(); //ÑÓʱº¯Êý³õʼ»¯ 14 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// ÉèÖÃÖжÏÓÅÏȼ¶·Ö×é2 15 uart_init(115200); //´®¿Ú³õʼ»¯Îª9600 16 LED_Init(); //³õʼ»¯ÓëLEDÁ¬½ÓµÄÓ²¼þ½Ó¿Ú 17 Init_PT6311(); 18 19 dspseg[0]=4;//temp 20 dspseg[1]='h'; 21 dspseg[2]='e';dspseg[3]='l'; 22 dspseg[4]='l';dspseg[5]='o'; 23 dspseg[6]='i';dspseg[7]='t'; 24 dspseg[8]='s';dspseg[9]='m'; 25 dspseg[10]='e';dspseg[11]='w'; 26 dspseg[12]=CONT|ALL|2;//ui 27 TransCoding(); 28 OpenStrobe_PT6311(); 29 WriteByte_PT6311(CMD_ModeSetting|0x0e);//15digits 13sg 30 31 OpenStrobe_PT6311(); 32 WriteByte_PT6311(CMD_DataSetting|0x04); //fixed addr 33 34 for (i=0;i<30;i++) 35 { 36 OpenStrobe_PT6311(); 37 WriteByte_PT6311(CMD_AddressSetting|ADDR[i]); 38 WriteByte_PT6311(dspbuf[i]); 39 } 40 OpenStrobe_PT6311(); 41 WriteByte_PT6311(CMD_DisplaySetting|0x08|0x07);//on 14/16 42 while(1) 43 { 44 if(USART_RX_STA&0x8000) 45 { 46 len=USART_RX_STA&0x3fff;//µÃµ½´Ë´Î½ÓÊÕµ½µÄÊý¾Ý³¤¶È 47 printf("what you have input is:\r\n"); 48 for(t=0;t<len;t++) 49 { 50 USART1->DR=USART_RX_BUF[t]; 51 while((USART1->SR&0X40)==0);//µÈ´ý·¢ËͽáÊø 52 } 53 if (strcmp("led",USART_RX_BUF)==0) 54 {printf("open led"); 55 OpenStrobe_PT6311(); 56 for (i=0;i<4;i++) 57 { 58 WriteByte_PT6311(CMD_DataSetting|0x01); 59 WriteByte_PT6311(~(1<<i));//open led 60 delay_ms(100); 61 } 62 for (i=0;i<4;i++) 63 { 64 WriteByte_PT6311(CMD_DataSetting|0x01); 65 WriteByte_PT6311(~(0x4>>i));//open led 66 delay_ms(100); 67 } 68 }else 69 if (strcmp("ds",USART_RX_BUF)==0) 70 { 71 OpenStrobe_PT6311(); 72 WriteByte_PT6311(CMD_ModeSetting|0x0e);//15digits 13sg 73 74 OpenStrobe_PT6311(); 75 WriteByte_PT6311(CMD_DataSetting|0x04); //fixed addr 76 77 for (i=0;i<30;i++) 78 { 79 OpenStrobe_PT6311(); 80 WriteByte_PT6311(CMD_AddressSetting|ADDR[i]); 81 WriteByte_PT6311(dspbuf[i]); 82 } 83 OpenStrobe_PT6311(); 84 WriteByte_PT6311(CMD_DisplaySetting|0x08|0x07);//on 14/16 85 }else 86 if (strcmp("key",USART_RX_BUF)==0) 87 { 88 OpenStrobe_PT6311(); 89 WriteByte_PT6311(CMD_DataSetting|0x02); 90 for (i=0;i<8;i++) 91 { 92 t=ReadByte_PT6311(); 93 printf(" k%d %d",i,t); 94 } 95 } 96 printf("\r\n");//²åÈë»»ÐÐ 97 USART_RX_STA=0; 98 for (t=0;t<len;t++) //if use strcmp the statement is absolutely 99 { 100 USART_RX_BUF[t]=0; 101 } 102 } 103 } 104 }
不足之处就是我现在没弄明白那个switch开关到底咋玩的,是不是一开始要么在高,然后切换,
以及按键也有问题,只有最低那个按下去是返回1 单独按第二个无效,一二一起按也能返回3,一次类推,
四个一起按返回15,我tm用的时候不可能这样来吧??
可能是我手册没理解,或者电路有点小问题,反正告一段落了
Last but now least:





有的图是在用的直流灯丝电压调式的,我写程序的时候都是用的直流,写好了之后才做出的灯丝电源
最后那张大图就是比较给力的了,实际更漂亮,扎米拍的!显然有些左右亮度就不一致!!!!
浙公网安备 33010602011771号