点阵之路_STC15单片机+8*16点阵+DS1302时钟

资源共享一下,8*16点阵系列的程序,自己参考例程写的,不太完善还望多多包涵!

链接:https://pan.baidu.com/s/1EisrLCBLPE5Ksp7bytjSXA  提取码:xx35

对应此文章应该是文件名字为下图的文件夹!


硬件介绍

1. 主控: STC15F2K60S2

      

2. 点阵: 1588BR 8*8点阵 经过测试发现型号为 788BS的8*8的点阵引脚也如下,可以通用,只是大小不一样!

       

3. 放大电路:S8050 NPN三极管,5.1k电阻,470Ω电阻。

4. 时钟电路:DS1302 时钟模块


实物图片

1. 主控,STC-15最小系统板

2. DS1302时钟模块

3. 点阵显示及放大部分(之前阳极用的1k的电阻,驱动电流有点大,三极管也烫手,导致点阵烧了很多LED,后来换成5.1k电阻,三极管也不那么烫了,这个只是初步的,后边在做点阵的话,可以用74HC138,或者TM1640(这个芯片特别好用),然后现在就想从基础的开始,自己焊接一下电路板什么的。)

4. 整体的,时间显示

5. 整体的,日期显示

6. 整体的,星期显示

7. 整体的,年份显示


设计思路

  • 程序简单电路图

大概的电路简图就是这个样子的,但是有一点需要特别注意

整个点阵模块的供电不要接在单片机最小系统上,需要另外接5V,或者3.3V单独供电,然后再与最小系统板共地。

如果点阵模块的供电接在最小系统,可能出现的问题是,单片机重新编译并下载程序后,可能程序还没开始运行,但是点阵已经通电了,出现的情况就是,点阵全灭,需要重新给点阵通电才可以,这个时候如果另外接点阵的供电电源即可解决问题!


点阵取模

行:第一块点阵和第二块点阵的阳极接一块,经过S8050,5.1K电阻接单片机P2口,最上边第一行是I/O口高位,取模时要注意!

列:两块点阵的阴极分别接S8050,5.1K电阻接到单片机,第一块接P0口,第二块接P1口,每块最左边均是I/O口最低位!

取模方式如下,不太懂的好好看看取模说明,另外,取模只跟硬件连接有关,一旦硬件确定,取模方式也随之固定,不会因为程序写法不一样而改变取模方式,之前我都把这点搞错了!

下边这个是我自己取的模,可以参考一下!想要什么图案,都可以自己用软件去画,或者直接用字符生成即可。

// 静态数组 数字库 3*8点阵取模
u8 code number_library[] = {
0x7F,0x41,0x7F,/*"0",0*/
0x21,0x7F,0x01,/*"1",0*/
0x4F,0x49,0x79,/*"2",0*/
0x49,0x49,0x7F,/*"3",0*/
0x78,0x08,0x7F,/*"4",0*/
0x79,0x49,0x4F,/*"5",0*/
0x7F,0x49,0x4F,/*"6",0*/
0x40,0x40,0x7F,/*"7",0*/
0x7F,0x49,0x7F,/*"8",0*/
0x79,0x49,0x7F,/*"9",0*/	
};

// 静态数组  中间冒号字库 	2*8点阵取模
u8 code sign_library[] = {
0x36,0x36,		/*   冒号    */
0x08,0x08,		/*    --    */
};	

// 静态数组  星期数组库		10*8点阵取模
u8 code week_library[] = {
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,/*"周一",0*/
0x04,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x04,/*"周二",0*/
0x02,0x22,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x22,0x02,/*"周三",0*/
0x7F,0x41,0x45,0x7D,0x41,0x41,0x7D,0x45,0x41,0x7F,/*"周四",0*/
0x00,0x21,0x29,0x29,0x3F,0x29,0x29,0x2F,0x21,0x00,/*"周五",0*/
0x11,0x12,0x14,0x18,0x70,0x70,0x18,0x14,0x12,0x11,/*"周六",0*/
0x00,0x00,0x7F,0x49,0x49,0x49,0x49,0x7F,0x00,0x00,/*"周日",0*/
};

程序

简单的对程序进行一个介绍,里边很多注释,应该可以看的懂。

  • 程序变量,数组定义

disbuffer_sign :是一个标志位,当标志位为0/1的时候,改变动态数组 disbuffer1 里边的内容,为1/0,改变 disbuffer2。这样做的好处是,当前正用于显示的 数组 不会在显示的时候被改变数组内容。防止乱码出现,比如正在显示 disbuffer1 数组里边的内容,就改变 disbuffer2 数组里边的内容。

u8 *disbuffer :全局指针,用来代替数组 disbuffer1,disbuffer2里边的内容。

如下图,在显示结束后,不要忘记把标志位取反!

disbuffer1,disbuffer2 :就是两个动态数组,用来储存要显示的内容。

table :用来存放行刷新的数据,对应的P2口,由于是第一行是最高位,所以第一行显示就是0x80,一次类推!

  • 延时函数

  • 定时器0初始化函数

要用到定时器0中断,每隔5ms,或者1ms进中断刷新一次显示函数,这样就不用每次写的时候就要考虑加显示函数了!

  • I/O口初始化函数

  • 显示刷新函数

这个函数也是放在中断处理里边的 显示刷新函数。

u8 *disbuff :定义在显示函数内部的局部指针变量,只用在此函数内,避免与全局指针变量重复,作用一样!

column1,column2是两块点阵的列全部清0,相当于初始化。

k1到k16则是16列,每一列对应 disbuff 数组里边的 模值,disbuff[0] & table[hang],则应该是行刷新的,只有在选中此行的时候才显示对应行的码值,如果不雨一下的话,可能出现乱码,可以自己尝试一下,反正是代码调试嘛,不在乎多下载几次。如果不知道为啥取模取出来是这个样子的话,你可以把每一列单独看作一个8位的二进制,把取出来的十六进制数代入进去,在对应一下显示出来的内容,应该就可以理解为啥这个模是这个样子的。

row = table[hang] :则是显示行刷新,然后 hang++,然后如果 hang > 7 的话,初始化为0,因为只有8行,这个可以根据实际需要更改!

  • DS1302 显示(时间,日期,星期,年份都类似)
/************************* DS1302时钟 时间显示 *************************************/
void Time_DS1302()
{
	
	if(disbuffer_sign == 1)
		disbuffer = disbuffer1;
	else
		disbuffer = disbuffer2;
	

	
	// 时 十位 列 1 2 3
	disbuffer[0] = number_library[(TIME[2]/16) * 3];
	disbuffer[1] = number_library[(TIME[2]/16) * 3 + 1];
	disbuffer[2] = number_library[(TIME[2]/16) * 3 + 2];
	
	disbuffer[3] = 0x00;
	
	// 时 个位 列 1 2 3
	disbuffer[4] = number_library[(TIME[2]%16) * 3];
	disbuffer[5] = number_library[(TIME[2]%16) * 3 + 1];
	disbuffer[6] = number_library[(TIME[2]%16) * 3 + 2];
	
	// 分 十位 列 1 2 3
	disbuffer[9] = number_library[(TIME[1]/16) * 3];
	disbuffer[10] = number_library[(TIME[1]/16) * 3 + 1];
	disbuffer[11] = number_library[(TIME[1]/16) * 3 + 2];
	
	disbuffer[12] = 0x00;
	
	// 分 个位 列 1 2 3
	disbuffer[13] = number_library[(TIME[1]%16) * 3];
	disbuffer[14] = number_library[(TIME[1]%16) * 3 + 1];
	disbuffer[15] = number_library[(TIME[1]%16) * 3 + 2];

	
	
	// 冒号 列 1 2
	if((TIME[0]%16) % 2)
	{		
		if(disbuffer_sign == 1)
			disbuffer = disbuffer1;
		else
			disbuffer = disbuffer2;
		
		disbuffer[7] = sign_library[0];
		disbuffer[8] = sign_library[1];

		disbuffer_sign = ~disbuffer_sign;
		
		delay(60000);
		delay(60000);
	}
	else
	{
		if(disbuffer_sign == 1)
			disbuffer = disbuffer1;
		else
			disbuffer = disbuffer2;
		
		disbuffer[7] = 0x00;
		disbuffer[8] = 0x00;

		disbuffer_sign = ~disbuffer_sign;
		
		delay(60000);
		delay(60000);
	}
	
	
//	// 秒 测试
//	disbuffer[9] = number_library[(TIME[0]/16) * 3];
//	disbuffer[10] = number_library[(TIME[0]/16) * 3 + 1];
//	disbuffer[11] = number_library[(TIME[0]/16) * 3 + 2];
//	
//	disbuffer[13] = number_library[(TIME[0]%16) * 3];
//	disbuffer[14] = number_library[(TIME[0]%16) * 3 + 1];
//	disbuffer[15] = number_library[(TIME[0]%16) * 3 + 2];
	
	disbuffer_sign = ~disbuffer_sign;
	
}

一共16列,每一列都送进去对应得数,另外要注意,DS1302模块的数组,TIME[ ],里边是BCD码,转换成十进制数,十位要除以16,个位要求余16!然后比如初始化的秒是 0x23,则要注意这个是十六进制的数,加满16才进一,因此求余16得到的是最后一个3,对应数组显示的字符码应该是第9个到第11个,因此要 *3 ,然后依次加1加2。同理除以16得到的是第一个数2,对应的数组从6开始,到8结束!

中间第7 8 列,冒号跟随秒数的变化而闪烁,当秒的个位为奇数的时候,冒号亮,偶数的时候灭,在这个里边也要分别更改两个动态数组,标志位也要随之取反。

这个上边注释掉的是对秒显示的一个测试,可以不用写这么多,可以直接在要显示的对应位置上,把TIME[ ]数组取出来的数改到秒就好!

  • 主函数

首先是对 I/O 口的初始化,定时器0的初始化,DS1302的初始化,接着在while循环里边,每次要先读取DS1302里边的时间,然后让时间显示30秒,日期显示10秒,星期显示10秒,年份显示10秒, 来回切换即可!

  • 定时器0中断

P2 也就是行,是对点阵的一个消隐程序,接着就是只有一个显示函数,每次定时满多长时间,就进来执行一次显示函数!


附录总结

1. 程序代码还可以优化一下,另外之前试过列刷新,没有行刷新显示的快,因此还有很多写代码的方式可以改进。

2. 一定不要让点阵的电流过大,我这个点阵就是烧坏了很多LED,需要控制一下电流大小!

3. 切换方式有点单一,后续学习过后会继续改进!

4. 有错误的地方还望指点,有不懂的也可以评论问我哦!

  • 2
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FightingBoom

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值