LED数码管段码计算器
前言
最近在复习单片机的知识,写编写LED数码管的驱动时,嫌计算太麻烦,就做了个WinForm项目
正文
原理
这里的LED数码管指的是8段数码管
我们可以看到每个LED数码管都是由7条线和一个点组成的,它们实际上都是LED灯(发光二极管),驱动一个LED数码管,就是点亮相应的LED灯。
LED数码管有两种连接方式,分别是共阴(cathode)、共阳(anode)
不难看出,若用共阳的连接方式,则向对应的管脚输入低电平,该led灯就会被点亮;相反,若使用共阳的连接方式,则需要向对应的管脚输入高电平,才能点亮led灯。
要使LED数码管显示数字“0”,则需要点亮a、b、c、d、e、f,若规定dp位为高位,a位为低位并且使用共阴的连接方式,那么此时的段码就是0011 1111,hex码为0x3f。若使用共阳的连接方式那么bin码就是1100 0000,hex码0xc0。可以看出,共阳的段码取反就是共阴了。
编程
UI长这样
PS:不要吐槽我
待合格的美术,谢谢
数码管呢,是自己写的用户控件,其实就是8个PictureBox(name分别是a、b、c、d、e、f、g、h),背景色什么的设置一下不就行了对吧(~ ̄▽ ̄)~,咳咳,这个控件类里面呢,有定义一个SegmentCode类,当然了,这个类也是我自己写的
public class SegmentCode
{
//这个是段码,我用字典存储它,用a,b,c,d,e,f,g,h来做键,0与1做值
public Dictionary<char, int> dic = new Dictionary<char, int>();
//这个枚举变量存储的是连接方式
public Ode ode;
public SegmentCode()
{
ode = Ode.anode; //默认共阳连接
for(int i = 0; i < 8; i++)
{
//初始化字典,默认都为熄灭状态,97是'a'的ASCII码
dic[(char)(97 + i)] = 0;
}
}
//这个方法看下文详解
public String getCode()
{
Int32 date = 0x00;
for (int i = 7; i >= 0; i--)
{
date <<= 1;
date |= dic[(char)(97 + i)];
}
if (ode.Equals(Ode.anode))
{
date = ~date;
}
String s = Convert.ToString(date, 16);
if(s.Length < 2)
{
return s.PadLeft(2,'0');
}
return s.Substring(s.Length - 2, 2);
}
}
public enum Ode
{
anode,
cathode
}
如何从字典转为hex码呢?由于我太菜了,所以想了很久,最后在学习EEPROM-IIC总线通讯,编写AT24C02的驱动时,发现了这个函数:
从中得到启发,解决了这个从字典转为hex的难题(笑)
来看看这个方法如何把字典转为hex码
假设现在遍历字典的结果是:
a:1
b:1
c:0
d:1
e:1
f:1
g:0
h:1
-
当i= =7时,date左移一位赋值给自身,最高位移出,最低位补0。即date==0000 0000
-
date按位或dic[‘h’] PS:104是’h’的ASCII码
date---|0000 0000
dic[h]-|0000 0001
result-|0000 0001
-
此时date==0000 0001
-
当i–,i= =6时,date左移位赋值,即date==0000 0010
-
date按位或dic[‘g’] PS:103是’g’的ASCII码
date---|0000 0010
dic[g]-|0000 0000
result-|0000 0010
-
此时date==0000 0010
-
同理,在循环结束时date==1011 1011
-
此时的date是共阴连接的bin码,如果是共阳连接,就对date取反赋值
String s = Convert.ToString(date, 16)
- 这句就是把date转为16进制格式的字符串
return s.Substring(s.Length - 2, 2);
- 如果是共阳连接,输出的结果可能前面有一大堆f,那是因为int32不是8位的,它占4个字节,即32位,所以取反之后,date==1111 1111 1111 1111 1111 1111 0100 0100,所以在正常结果之前会有6个f多出来,我们只需要倒数两位数字就行了
return s.PadLeft(2,'0');
- 如果位数不够两位,就补0
因为懒,我就把8个PictureBox的单击事件全写一个了,无非是改变颜色,改变状态,另外两个就是获取hex码的方法和设置连接方式,没啥好说的。
SegmentCode seg = new SegmentCode();
Ode ode = Ode.anode;
private void ClickProce(object sender,EventArgs e)
{
//sender实际上就是PictureBox本Box
PictureBox pbox = sender as PictureBox;
if (pbox.BackColor.Equals(SystemColors.ControlDark))
{
pbox.BackColor = Color.Red;
//pbox.Name.ToCharArray()[0]实际上就是PictureBox的Name了(即a、b、c、d、e、f、g、h)
this.seg.dic[pbox.Name.ToCharArray()[0]] = 1;
}
else
{
pbox.BackColor = SystemColors.ControlDark;
this.seg.dic[pbox.Name.ToCharArray()[0]] = 0;
}
}
public String getHexCode()
{
seg.ode = this.ode;
return seg.getCode();
}
public void SetOde(Ode ode)
{
this.ode = ode;
}
接下来就是控件使用了
private void calc_Click(object sender, EventArgs e)
{
if(this.cathode.Checked)
{
this.led1.SetOde(Ode.cathode);
}
else if(this.anode.Checked)
{
this.led1.SetOde(Ode.anode);
}
this.date.Text = "HexCode: " + this.led1.getHexCode();
}
看看效果