suncat0504 发表于 2021-1-8 09:03 我学的按键检测是用状态机的方式实现的,网上说判断按键按下后,给一个标志位,蜂鸣器用npn管驱动,给高就响,低就不响,又不能像LED灯一样io口取反,给了1以后,多久给0,还是在按键松手后也给个标志位? |
dcjdcj 发表于 2021-1-7 22:14 你下载的程序里,在主函数中不是有按键的监察处理吗?从按下到松开的整个过程,都有代码。你只要在防抖动检查的Key==0的判断之后,开启声音;在确认松开之后(while(Key==0);)架上停止声音的代码不就可以了吗? if (Key==0) { // 检查按键是否按下 delayms(20); // 防抖的延时,防止因为异常干扰引起的误触发动作 if (Key==0) { // 在防抖之后,再次确认按键是否真的被按下 打开声音(); // 按键被按下,开始播放声音 while(Kewy==0); // 直到按键松开后,才执行“关闭声音();”开始处的代码 关闭声音(); // 按键已经被松开,停止i播放声音 ... // 按键被按下后,执行对应的处理机能 } } |
suncat0504 发表于 2021-1-7 20:41 3位的我也懂了,非常谢谢你,还想请教一个问题:就有源蜂鸣器怎么实现检查到按键按下响,长按就一直响直到松手为止,这个问题也困扰了我好久,网上也没有找到解决的方法,有一个多月了,现在也没有想出怎么驱动,难道是我不适合这条路吗 |
dcjdcj 发表于 2021-1-7 18:44 程序稍加改动,就可以变成驱动四位数字的。// 保存四位数字的数组变量 u8 v[4]={2,3,4,5}; void getValue(void) { v[0]=val/1000; v[1]=(val%1000)/100; v[2]=(val%100)/10; v[3]=val%10; } void main() { // 初始化595控制管脚 DATA=0; CLK=0; LOCK=0; getValue(); // 获得显示数值 while(1) { // 按键按下,累加数据 if (Key==0) { delayms(5); // 防抖 if (Key==0) { while(Key==0); // 等待按键松开 val++; // 累加1 getValue(); // 获得显示数值 } } disp(); } } disp函数中,计算行显示数据的地方: // 循环行 for (row=0; row<8; row++) { // 根据显示数值,计算每行的点阵数据。一行两个字节,16Bit位对应16列 // col_data[row][0]对应第一个595,col_data[row][1]对应第二个595. // 因为是级联,所以从col_data[row][1]到col_data[row][0],从Bit0到Bit7串行输出 //col_data[row][0]=(Table[v[0]][row]<<3) | (Table[v[1]][row]>>2); //col_data[row][1]=(Table[v[1]][row]<<6) | (Table[v[2]][row]<<1); col_data[row][0]=(Table[v[0]][row]<<4) | (Table[v[1]][row]); col_data[row][1]=(Table[v[2]][row]<<4) | (Table[v[3]][row]); } 编译、执行proteus模拟后,就会看到显示结果。每按动一次按钮,显示数据+1. |
dcjdcj 发表于 2021-1-7 18:44 这是我刚刚测试过的程序,已经用proteus模拟过了。你可以试试。 |
66.68 KB, 下载次数: 11
2个595显示3位数字
suncat0504 发表于 2021-1-7 14:40 唉,刚入坑小白一枚,理论经验都不足 |
dcjdcj 发表于 2021-1-6 23:57 显示原理通了,下一步就是怎么用程序用合理的逻辑实现的问题了,对吗?这不就是程序员要做到的事情吗? |
suncat0504 发表于 2021-1-4 23:20 非常感谢您的耐心解答,这样是可以一个595显示两个字了,但是不能把1号595的数据移到2号上面,不能实现自由显示的目的
|
suncat0504 发表于 2021-1-6 10:06 看了一些教程,说是可以开一个16字节缓存,再映射到每一列上,但是我这个是发一个字节是横向排列的,不改电路的情况下可以实现一列一列的扫描吗?如果这样,就可以控制每一列显示的内容了,就可以显示任意的内容了 |
dcjdcj 发表于 2021-1-5 22:12 是啊,你想要的这个变量,不就是数组pix的以为元素的下标吗? 变量num1=2; 那么pix[num1]不就是pix[2]吗?编程要灵活一些。 |
suncat0504 发表于 2021-1-4 23:20 比如5*7的字体,16列可显示3个数字,这3个数字用变量去控制其显示的内容 |
本帖最后由 suncat0504 于 2021-1-4 23:26 编辑 如果不想用点阵模式保存,也可以用字节数据保存,比如 数字2的各行数值 pix[2] = {0, 6,9, 1, 2, 4, 8, 15} 数字3的各行数值 pix[3] = {0 6 , 9, 1, 2, 1, 9, 6 } 数字4的各行数值 pix[4] = {0, 6, 10, 10, 10, 15, 2, 2} 显示234的时候,第二行的点阵数据: 第一个595 = (pix[2][1]<<3) | (pix[3][1]>>2) ; // 6<<3 | 6>>2=49=0x31; 第一个595 = (pix[3][1]<<6) | (pix[4][1]<<1);; // 6<<6 | 6<<1=140=0x8c 这样的效果是一样的。(注意,移位操作,是不带进位的移位) |
本帖最后由 suncat0504 于 2021-1-5 18:42 编辑 图片说明更容易理解,第五行16进制数错了,是0x20, 0x5E |
4x8点阵数字的扫描.jpg (191.17 KB, 下载次数: 81)
实际上,pix也可以被定义为一位数组,而一位数组的每个元素是另一个二维数组(对应4 x 8的点阵数据)。这样处理,可能更容易一些。 |
dcjdcj 发表于 2021-1-3 20:32 自己组织点阵数据对应数字,需要预先把每个数字的点阵数据以0和1的方式建立出数组,对4列8行,每个数字张勇一个二维数组,比如对于数字2的点阵数据: pix[2]={{0,0,0,0}, {0,1,1,0}, {1,0,0,1}, {0,0,0,1}, {0,0,1,0}, {0,1,0,0}, {1,0,0,0}, {1,1,1,1} } 把所有数字弄到一起,组成一个三维数组,方便按照下标定位数字所在元素,组成字节数据。 当需要显示234时, 先取第一行像素数据,依次把0、pix[2]的第0行像素的四列,0,pix[3]的第0行像素的前两列,0,共计8Bit位,放到第一个595 再取pix[3]的第0行像素的后两列,0,pix[4]的第0行像素的四列,0,共计8Bit位,放到第二个595中, 这样234的第一行就都被设置好了;接着是其他各行的像素数据,也按照这种方式组织并显示,最终,“234”就被显示出来了。 |
本帖最后由 suncat0504 于 2021-1-5 18:41 编辑 dcjdcj 发表于 2021-1-3 20:32 原理我已经和你说了。点阵显示数字字符,无非就是逐行逐列把像素点的数据传递给显示部件。 一个595对应一个字节,就是8个bit位。两个对应16个Bit位。当每个字符、数字占用一个字节8Bit位的时候,每个595一次只能显示一个一行8列的像素点,逐行扫描,视觉暂留现象,呈现出一个完整的字符。 当一个字符使用4x8方式显示的的时候。这个字符每一行占用4个像素点,共8行就能完整显示一个字符。那么两个595,就能同时显示4个字符了。实际使用,为了避免太紧凑,我加了一行空白行,就是全0的那行。数字之间间隔一个空白列,数字最后还有一个空白咧,就是在垂直方向上全都为0的那些列。 比如,使用我提供的点阵组合,对234这个数值的组合,我只用0和1来表达, 0表示不亮,1表示亮: 0 1234 5 6789 A BCDE F // 这行是以16进制表示Bit位的编号 ------------------------------ 0 0000 0 0000 0 0000 0 // 第0行 从这行开始,表示的是像素数据,0-不亮;1-亮;这样是空白行。 0 0110 0 0110 0 0110 0 // 第1行 0 1001 0 1001 0 1010 0 // 第2行 0 0001 0 0001 0 1010 0 // 第3行 0 0010 0 0010 0 1010 0 // 第4行 0 0100 0 0001 0 1110 0 // 第5行 0 1000 0 1001 0 0010 0 // 第6行 0 1111 0 0110 0 0010 0 // 第7行 你注意看由1组成的图形是不是2、3、4? 按照这个点阵数据,你只需要把每行的数据拆分为两个字节,分别提供给595即可。 这样。为了显示234,把以下数据逐行提供给两个595 0x00 0x00 // 第0行,,对应000000000000 0x31 0x8C // 第1行,对应0 0110 0 011 0 0 0110 0 0x4A 0x54 // 第2行 对应0 1001 0 1001 0 1010 0 0x08 0x54 // 第3行 对应0 0001 0 0001 0 1010 0 0x10 0x94 // 第4行 0 0010 0 0010 0 1010 0 0x20 0x5E // 第5行 0 0100 0 0001 0 1110 0 0x42 0x44 // 第6行 0 1000 0 1001 0 0010 0 0x79 0x84 // 第7行 0 1111 0 0110 0 0010 0 那么,在16*8的点阵LED上现实的就是234数字了。其中第0、5、A、F列是空白列。 |
suncat0504 发表于 2021-1-3 14:17 2个595是16位,每次发8位,如果只显示2位数字,那好办,我不明白的是如何把16位原本显示两位数字的拆成显示3位数字,就是说我只能用一个595来控制显示1位数字,如果要让2个595来显示3位数,这个就不懂了,不知道怎么写这个驱动程序 |
人人学会单片机 发表于 2020-12-31 11:35 行扫描我没有写出来,两个595是列扫描,如果2个595只显示2个数字,我会写驱动,但是2个595要显示3个数字,我没不知道怎么写了,请赐教 |
我很想知道,你两个595怎么驱动16*8点的?正反都驱动? 说说你的问题,你可以开辟一个16字节的数组,分别对应每一列。595就负责把每一列的字节显示到16*8点LED上去,这样,至于你显示什么图案,那就跟595无关了。你只需要往数组里面填充字节值就行了。 具体操作,建议你学习《人人学会单片机》视频教程,第13、14、15、16课程,就是这样操作的。 |
3位数字可自由控制 |