数码之家

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信登录

微信扫一扫,快速登录

搜索
查看: 2442|回复: 11

[C51] 基于STC8H4K64TL的电子琴开源

[复制链接]
头像被屏蔽
发表于 2023-3-17 14:47:36 | 显示全部楼层 |阅读模式
本帖最后由 疯狂的兔子来了 于 2023-3-17 14:49 编辑

STC开源电子琴:
最早看中这颗芯片最主要的就是看中了触摸,因为之前做过好多项目都需要用到触摸,那这里也算是为了以后的项目做个铺垫,那么首先我们先把触摸部分焊接起来。

原理图如下:

PCB绘制


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x
发表于 2023-3-17 15:56:53 | 显示全部楼层
没有数字音源(波表),效果太?
回复 支持 反对

使用道具 举报

发表于 2023-3-20 00:24:05 | 显示全部楼层
我是来看和弦的
回复 支持 反对

使用道具 举报

发表于 2023-3-20 02:51:51 | 显示全部楼层
真不能让技术宅设计乐器。
回复 支持 反对

使用道具 举报

头像被屏蔽
 楼主| 发表于 2023-3-20 09:43:03 | 显示全部楼层
duckyer1 发表于 2023-3-17 15:56
没有数字音源(波表),效果太?

是的,现在暂时还是用的做简单的读乐谱的方式,还没做波表,等音频的芯片到了,再弄个波表测试下
回复 支持 反对

使用道具 举报

头像被屏蔽
 楼主| 发表于 2023-3-20 09:46:33 | 显示全部楼层
kpj001 发表于 2023-3-20 02:51
真不能让技术宅设计乐器。

这是简易开发板,主要是让您看看STC强大的触摸和PWM,ADC等功能。 您也可以找我申请个免费的样片来做个更精致的版本,我们帮您推广!
回复 支持 反对

使用道具 举报

头像被屏蔽
 楼主| 发表于 2023-3-20 15:14:02 | 显示全部楼层
波形测试视频如下:
声音测试结果如下:

测试:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x
回复 支持 反对

使用道具 举报

发表于 2023-3-20 16:15:30 | 显示全部楼层
stc宣传经费充足啊,马力全开,已经在几个论坛看到推广
回复 支持 反对

使用道具 举报

发表于 2023-3-20 17:04:58 | 显示全部楼层
疯狂的兔子来了 发表于 2023-3-20 09:46
这是简易开发板,主要是让您看看STC强大的触摸和PWM,ADC等功能。 您也可以找我申请个免费的样片来做个更 ...

不不不,单片机真不适合做乐器,免费也不行! 不然那些软波表,硬波表,音效公司还不得倒闭了。
回复 支持 反对

使用道具 举报

头像被屏蔽
 楼主| 发表于 2023-3-21 08:38:45 | 显示全部楼层
kpj001 发表于 2023-3-20 17:04
不不不,单片机真不适合做乐器,免费也不行! 不然那些软波表,硬波表,音效公司还不得倒闭了。 ...

所以啊,单片机才是王道,什么功能都可以实现
回复 支持 反对

使用道具 举报

发表于 2023-3-24 08:46:16 | 显示全部楼层
单片机真是牛,只有你想不到,没有它做不到。
回复 支持 反对

使用道具 举报

头像被屏蔽
 楼主| 发表于 2023-3-24 08:54:58 | 显示全部楼层
六、数码管调试
紧接着上面,我们已经把下载部分都测试完成了,那么今天我们开始下一个部分的测试,首先我们先把硬件电路焊起来(由于一点点小失误,数码管只买了个共阳的,共阴的还在购物车里躺着,很尴尬,已经加急买下去了),最后数码管焊完之后成品如下(新焊接的部分如图红圈部分所示,包含原理图上的限流电阻和数码管部分,都是手册推荐的规格):

硬件部分焊完了,然后找个驱动代码测试一下,看看能不能点亮先。既然之前直接down的官网的原理图,那就再去把官网的那个配套的程序也下下来用着:

因为考虑到我们的板子和官方的板子引脚也用的差不多,那直接历程下载进去应该就能直接用,话不多说,直接冲,反正下载程序下错了既不会死机,也不会炸机,下就完了,下载完之后,数码管显示了这:


可以看到我们的程序部分如上,既然工程名称叫“16个触摸按键16个灯-8个共阴-8个共阳数码管显示”,那么推测程序就是一半灯驱动,一半触摸驱动,秉承着这个思路,我们开始分析程序,就看main开始的部分。
void main(void)
{
        u8        i;
        u16        j;


        P_SW2 |= 0x80;        //允许访问XSFR(扩展特殊功能寄存器)


//        XOSCCR = 0xc0;           //启动外部晶振
//        while (!(XOSCCR & 1));   //等待时钟稳定
//        CLKDIV = 0x00;           //时钟不分频
//        CKSEL = 0x01;            //选择外部晶振


        P0M0 = 0x00;
        P0M1 = 0x00;


<font color="#ff0000">        P2n_push_pull(0xff);        //COM0~COM7线设置为推挽输出
        P4n_push_pull(0xff);        //SEG0~SEG7(P4.0~P4.7)线设置为推挽输出
        P3n_push_pull(0xf0);        //SEG12~SEG15(P3.4~P3.7)线设置为推挽输出


        P2DR = 0x00;        //COM0~COM7线设置为强电流驱动
        P4DR = 0x00;        //SEG0~SEG7线设置为强电流驱动
        P3DR = 0x0f;        //SEG12~SEG15线设置为强电流驱动


        COMEN  = 0xff;        //允许8个COM
        SEGENL = 0xff;        //允许8个SEG 低字节
        SEGENH = 0xf0;        //允许8个SEG 高字节
        LEDCTRL = 0x80 + (2<<4) + 0;        //B7=1: ON,  B5 B4: 0共阴, 1共阳, 2共阴共阳, 3保留, B2 B1 B0: 0占空比100%, 1~7占空比7/8~1/8
        LEDCKS = 8;                //数码管COM扫描显示的主频时钟数 = 160*9*LEDCKS, 每个COM显示时间=1440*LEDCKS/fosc(MHz) us, COM扫描频率=fosc/(1440*LEDCKS *COM数).
                                        //例如 fosc = 11.0592MHz, 8个COM, LEDCKS = 8, 则每个COM显示时间=1440*8/11.0592 = 1042 us, COM扫描频率=11059200/(1440*8*8)=120Hz.
                                        //已知扫描时间t(us)计算 LEDCKS = t*fosc(MHz)/1440, 比如fosc = 24MHz, 要求1个COM扫描1ms, 则 LEDCKS = 1000*24/1440 = 16.7, 取整数17.


        for(i=0; i<8; i++)
        {
                LoadLED_A(i,i);                //共阳,显示01234567
                LoadLED_B(i,i+8);        //共阳,显示89ABCDEF
        }
        COM4_DAH_tmp = 0;
        COM5_DAH_tmp = 0;
        COM6_DAH_tmp = 0;
        COM7_DAH_tmp = 0;</font>




<font color="#9acd32">        P1n_pure_input(0xff);        //Touch Key设置为高阻
        P5n_pure_input(0x0f);
        P0n_pure_input(0x0f);


//        TSCHEN = 0xffff;        //TK0~TK15
        TSCHEN1 = 0xff;                //TK0~TK7
        TSCHEN2 = 0xff;                //TK8~TK15
        TSCFG1  = (7<<4) + 6;        //开关电容工作频率 = fosc/(2*(TSCFG1[6:4]+1)), 放电时间(系统时钟周期数) 0(125) 1(250) 2(500) 3(1000) 4(2000) 5(2500) 6(5000) 7(7500) 最小3
        TSCFG2  = 1;                //配置触摸按键控制器的内部参考电压(AVCC的分压比), 0(1/4)  1(1/2)  2(5/8)  3(3/4)
//        TSCTRL = (1<<7) + (1<<6) +3;        //开始扫描, B7: TSGO,  B6: SINGLE,  B5: TSWAIT, B4: TSWUCS, B3: TSDCEN, B2: TSWUEN, B1 B0: TSSAMP
//        TSRT = 0x00;                //没有LED分时扫描
        IE2 |= 0x80;                //允许触摸按键中断
        EA = 1;


        delay_ms(50);
//        B_TK_Lowpass = 0;        //禁止低通滤波
        B_TK_Lowpass = 1;        //允许低通滤波
        for(read_cnt=0; read_cnt<40; read_cnt++)                //读40次键, 将此值作为未触摸时的0点, 要求上电时不要触摸按键
        {
        //        TSCTRL = (1<<7) + (1<<6) +3;        //开始扫描, 4次平均, 读数大约为无平均的一半
                TSCTRL = (1<<7) + (1<<6) +1;        //开始扫描, 2次平均, 读数大约为无平均的一半
        //        TSCTRL = (1<<7) + (1<<6);                //开始扫描, 只转换1次, 无平均
                B_ReadKeyOk = 0;
                for(i=0; i<100; i++)
                {
                        if(B_ReadKeyOk)        break;
                        delay_ms(1);
                }
        }
        for(i=0; i<16; i++)                TK_zero = TK_cnt;        //保存0点
        
        B_TK_Lowpass = 1;        //允许低通
        KeyState = 0;
        read_cnt = 0;</font>
        
<font color="#9acd32">        B_ReadKeyOk = 0;
        KeyValue = 10;
        KeyCode = 0;
        ShowKey();</font>
        
        while (1)
        {
<font color="#dda0dd">                delay_ms(1);
               
                if(++TrigLimit >= 100)        //触发转换
                {
                        TrigLimit = 0;
                //        TSCTRL = (1<<7) + (1<<6) +3;        //开始扫描, 4次平均, 读数大约为无平均的一半
                        TSCTRL = (1<<7) + (1<<6) +1;        //开始扫描, 2次平均, 读数大约为无平均的一半
                //        TSCTRL = (1<<7) + (1<<6);                //开始扫描, 只转换1次, 无平均
                }
               
                if(B_ReadKeyOk)                        // 16个键都转换完毕
                {
                        B_ReadKeyOk = 0;
                        TrigLimit = 100;
                        ShowValue(KeyValue);        //显示读数


                        j = KeyState;                //读入上一次键状态
                        for(i=0; i<16; i++)
                        {
                                if(TK_zero > TK_cnt)        //计算与0点的差值
                                {
                                        TK_zero--;        //缓慢0点跟随
                                                 if((TK_zero - TK_cnt) >= T_KeyPress/2)        KeyState |=  T_KeyState;        // 大于按键读数变量的1/2就是按下
                                        else if((TK_zero - TK_cnt) <= T_KeyPress/3)        KeyState &= ~T_KeyState;        // 小于按键读数变量的1/3就是释放
                                }
                                else
                                {
                                        KeyState &= ~T_KeyState;
                                        if((TK_cnt - TK_zero) > 100)        TK_zero += 50;        //差别很大, 则快速回0点
                                        else                                                                TK_zero += 10;        //差别不大, 则慢速回0点
                                }
                        }
                        j = (j ^ KeyState) & KeyState;        //检测键是否按下
                        if(j != 0)
                        {
                                KeyCode = CheckKey(j);        //计算键码 1~16
                                i = (u8)j;
                                COM4_DAH_tmp ^= (i << 4);
                                COM5_DAH_tmp ^= (i & 0xf0);
                                i = (u8)(j >> 8);
                                COM6_DAH_tmp ^= (i << 4);
                                COM7_DAH_tmp ^= (i & 0xf0);
                                
                                COM4_DAH = COM4_DAH_tmp;
                                COM5_DAH = COM5_DAH_tmp;
                                COM6_DAH = COM6_DAH_tmp;
                                COM7_DAH = COM7_DAH_tmp;
                                
                                ShowKey();
                                if(KeyCode == 15)
                                {
                                        KeyValue--;                        //显示数值的键号-1
                                        KeyValue &= 0x0f;
                                        ShowValue(KeyValue);        //显示读数
                                }
                                if(KeyCode == 16)
                                {
                                        KeyValue++;                        //显示数值的键号+1
                                        KeyValue &= 0x0f;
                                        ShowValue(KeyValue);        //显示读数
                                }
                        }
                }</font>
        }

}

我们通过注释和函数的名称,变量名称等,我们把程序分为如上三块,红色的部分就是数码管(LED)驱动,绿色的部分就是触摸的驱动,最后while里面那个紫不紫,粉不粉(暂且叫他粉紫色,或者有谁知道这个具体叫啥的下边留言告诉我下)的就是数码管和触摸的组合的用户功能,那我们现在只测数码管,先把上面绿色和粉紫色的代码屏蔽掉,在下载进去看下效果如下:

这时候可以看到数码管显示贼稳了,说明这个代码基本可以用,给官方点个赞undefined剩下的小细节我们就可以慢慢的通过测试对比然后修改了。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册 微信登录

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-7-26 13:20 , Processed in 0.171600 second(s), 11 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

快速回复 返回顶部 返回列表