⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.asm

📁 汇编语言实现的电子音乐发生器
💻 ASM
📖 第 1 页 / 共 2 页
字号:
;********** 单片机电子琴 *********************
 include "define.asm"

;*************** 复位向量和中断向量 *****************
 org 000h
 nop
 goto main
 ;org 0004h
 ;goto serv 
;**************** main ****************
main
  bsf status,rp0;bank1
  movlw 07h
  movwf adcon1 ;设置lcd
  bcf status,rp0;bank0
  call lcdinitiate ;lcd 初始化
  call functlist ;功能显示界面
  movlw  b'00000001';清屏
  call   lcddownwrite;下降触发并写入
  
  bsf status,rp0;bank1
  movlw 00h;将端口C设置为输出
  movwf trisc;
  movlw 0ffh;将端口B设置为输入
  movwf trisb;
  
  movlw 02h;设置选项寄存器:上拉电阻启用;INT下降沿触发
  movwf option_reg;分频器给TMR0;分频比值设为1:8
  bcf status,rp0;恢复到文件寄存器的体0

  ;movlw h'b0'
  ;movwf intcon  ;开放INT和全局中断使能位

;**************************
 movlw 0dbh;"0"键的行列码
 movwf 40h;0的地址
 movlw 77h;"1"
 movwf 41h;
 movlw 7bh;"2"
 movwf 42h;
 movlw 7dh;“3”
 movwf 43h;
 movlw 7eh;“4”
 movwf 44h;
 movlw 0b7h;“5”
 movwf 45h;
 movlw 0bbh;“6”
 movwf 46h;
 movlw 0bdh;“7”
 movwf 47h;
 movlw 0beh;“8”
 movwf 48h;
 movlw 0d7h;“9”
 movwf 49h;
 movlw 0ddh;“A”
 movwf 4ah;
 movlw 0deh;“B”
 movwf 4bh;
 movlw 0e7h;“C”
 movwf 4ch;
 movlw 0ebh;“D”
 movwf 4dh;
 movlw 0edh;“E”
 movwf 4eh;
 movlw 0eeh;“F”
 movwf 4fh;
;********************************
;******** 判断与功能选择 *********
loopmain
  
  call check
  clrf special
  movlw 0ddh;"A"高音
  subwf value,0
  btfsc status,z
  call fenpin4

  movlw 0deh
  subwf value,0
  btfsc status,z
  call fenpin8

  movlw 0e7h
  subwf value,0
  btfsc status,z
  call fenpin16

  movlw 0ebh;"D"存储
  subwf value,0
  btfsc status,z
  call writein

  movlw 0edh;"E"播放
  subwf value,0
  btfsc status,z
  call song
  
  movlw 0h;;送0h到W--------由特殊操作判断寄存器是否为0判断是否为特殊操作(因为进入特殊操作时都会给PANDUAN加1)
  subwf special,0;special-W值送W
  btfss status,z;看Z位是否为1,是!跳一步
  goto loopmain

  call dzq;默认模式电子琴
  
  goto loopmain
  
;******************* serv ************************
;*************中断服务子程序************
serv
;*********保护现场**********
 movwf w_temp;保护W
 swapf status,w;保护STATUS
 clrf status;选择体0
 movwf status_temp;将STATUS存入体0的备份寄存器
;**********调查中断源**********
 btfsc intcon,intf;检查是不是INT中断
 goto intserv;是!跳转到INT中断处理部分
 goto retfie0;其他情况均中断返回
;*************INT中断处理部分************
intserv;外部中断处理程序片段入口
 clrf portc;令全部LED熄灭
 bsf portc,6;点亮第六只LED,表示就绪 
loopint 
 bsf status,rp0;bank1 
 movlw 02h;设置选项寄存器:上拉电阻启用;INT下降沿触发
 movwf option_reg;分频器给TMR0;分频比值设为1:8
 bcf status,rp0

 call check;调用键盘程序
 movlw 77h;是不是1键按下?
 subwf value,0;
 btfsc status,z;
 call song1;是!播放歌曲1
 movlw 7bh;否!是不是2键按下?
 subwf value,0;
 btfsc status,z;
 call song2;是!播放歌曲2
 bcf intcon,intf;清除INTF中断标志位
 goto retfie0;中断返回

;**********恢复现场***********
retfie0  
 swapf status_temp,w;恢复STATUS
 movwf status;
 swapf w_temp,f;恢复W
 swapf w_temp,w;
 ;movlw b'10010000';重新开放全局和INT中断
 ;movwf intcon
 retfie;中断返回

;******************** 电子琴 ************
;*******************************************
dzq      
 movf fsr,0;将翻译键值送到W
 call checkyinch;;查表得对应音长
 movwf count;;通过W传给参数COUNT
 movf fsr,0;;将翻译键值送到W
 call checkyingao;;查表得对应音调(频率决定高低)
 movwf temp0;;通过W传给参数TEMP0
 call fangbo;;调用FANGBO子程序
 return;;发一个单音完毕,返回到loopmain
;********************************
checkyinch;;对应音长
 addwf pcl,1 ;地址偏移量加当前PC值
 nop
 retlw .100;单音‘1’
 retlw .112;单音‘2’
 retlw .126;单音‘3’
 retlw .134;单音‘4’
 retlw .150;单音‘5’
 retlw .168;单音‘6’
 retlw .189;单音‘7’
 retlw .200;单音高音‘1’
;*************************************************
checklcd
              addwf   pcl,1              ;地址偏移量加当前PC值
              retlw   b'01001111'        ;'0'的LCD显示码
              retlw   b'00110001'        ;'1'的LCD显示码
              retlw   b'00110010'        ;'2'的LCD显示码
              retlw   b'00110011'        ;'3'的LCD显示码
              retlw   b'00110100'        ;'4'的LCD显示码
              retlw   b'00110101'        ;'5'的LCD显示码
              retlw   b'00110110'        ;'6'的LCD显示码
              retlw   b'00110111'        ;'7'的LCD显示码
              retlw   b'00111000'        ;'8'的LCD显示码
              retlw   b'00111001'        ;'9'的LCD显示码
              retlw   b'01000001'        ;'A'的LCD显示码
              retlw   b'01000010'        ;'B'的LCD显示码
              retlw   b'01000011'        ;'C'的LCD显示码
              retlw   b'01000100'        ;'D'的LCD显示码
              retlw   b'01000101'        ;'E'的LCD显示码
              retlw   b'01000110'        ;'F'的LCD显示码
 
checkyingao;;对应音调
 addwf pcl,1  ;地址偏移量加当前PC值
 nop
 retlw .100;;单音‘1’
 retlw .117;;单音‘2’
 retlw .132;;单音‘3’
 retlw .139;;单音‘4’
 retlw .152;;单音‘5’
 retlw .163;;单音‘6’
 retlw .173;;单音‘7’
 retlw .178;;单音高音‘1’
;**********************************************
;***********键盘部分***********************
check
 call keyscan;调用键盘扫描子程序
 comf value,0;位置码取反送W
 btfsc status,z;测试有键按下否?有!跳过下条指令
 goto check;无!则循环检测
 movlw .13
 movwf data1
 call delaytemp;调用延时子程序,消除接通抖动的影响
 call keyscan;再次调用键盘扫描子程序
 comf value,0;位置码取反送W
 btfsc status,z;测试有键按下否?有!跳过下条指令
 goto check;无!则循环检测
 call translate;调用键值翻译子程序
 call lcdshow
 return
;**************************************************
lcdshow
 bsf status,rp0
 movf option_reg,w
 bcf status,rp0;恢复到文件寄存器的体0
 movwf option_temp
 bsf status,rp0;设置文件寄存器的体1
 movlw  7h
 movwf  option_reg;设置定时器tmr0分频比为1:256
 bcf status,rp0;恢复到文件寄存器的体0


 call lcdinitiate
  movlw  b'00000001';清屏
  call   lcddownwrite;下降触发并写入

 movf fsr,w
 call checklcd
 call enableport


 bsf status,rp0
 
 movlw 0ffh;将端口D设置为输入
 movwf trisd;
 bcf status,rp0
 
 movf option_temp,w
 bsf status,rp0
 
 movwf option_reg
 bcf status,rp0
 return
 
;*****************************************************
;*****************************************
;***出口参数:有按键按下时寄存器value=按键行列码;
;***无键按下时value=ffh
;**************************************
keyscan
 ;bcf intcon,7;屏蔽全局中断

 bcf status,rp1;设置文件寄存器的体1
 bsf status,rp0;
 bcf option_reg,rbup;启用B口上拉电阻
 movlw 0fh;将端口B的方向控制码0FH先送W
 movwf trisb;将其设为高四位出低四位入
 movlw 0fh;将端口D的方向控制码0FH先送W
 movwf trisd;将其设为高四位出低四位入
 bcf status,rp0;恢复到文件寄存器的体0
 movlw 00h;四条行线全部输出0
 movwf portd;
 nop;等待输出状态稳定下来
 nop;
 movf portb,0;读取列线状态
 andlw 0fh;屏蔽掉高四位
 movwf value;得到的列码暂存到VALUE寄存器中
 xorlw 0fh;与0FH值对比
 btfsc status,z;列码全为1吗?否!有键按下
 goto nokey;是,无键按下
 bsf status,rp0;设置文件寄存器的体
 movlw 0f0h;将端口B的方向控制码0F0H先送W
 movwf trisb;将其设为高四位入低四位出
 movlw 0f0h;将端口D的方向控制码0F0H先送W
 movwf trisd;将其设为高四位入低四位出
 bcf status,rp0;恢复到文件寄存器的体0
 movf value,0;读取列码
 movwf portb;再经过列线输出
 nop;
 nop;
 movf portd,0;读取行线状态
 andlw 0f0h;屏蔽掉低四位
 iorwf value,1;将行码和列码组合起来并放入VALUE
 return;子程序返回
nokey
 movlw 0ffh;建立一个标志值,表明无键按下
 movwf value;
 bsf status,rp0
 clrf trisd
 bcf status,rp0
 ;bsf intcon,7

 return
;**********************************************************
;******* 出口参数:正常时寄存器fsr=键值(在table中的偏移量
;********** 失常时寄存器fsr=aah
;***********************************************************
translate
 movlw 40h;地址指针FSR设置表头地址
 movwf fsr;也就是给文件选择寄存器FSR设置初始值
loopt1
 movf 0,0;以间接寻址方式读表,并放入W
 xorwf value,0;与位置码比较
 btfsc status,z;相等吗?否!跳一步
 goto loopt2;是!跳转
 incf fsr,1;地址指针FSR递增
 btfss fsr,4;查到末尾了吗,即够16次了吗?(BIT4=1?)
 goto loopt1;否!跳回继续查表
 movlw 0aah;是!位置码超限(可能多键同时按下)
 movwf fsr;返回一个“AAH=10101010B”值作标志
 return;子程序返回
loopt2
 bcf fsr,6;等效于FSR—40H(即01000000B)—>FSR
 return; 在FSR中获得键值,返回
;*************方波**************
;出口参数:rc4输出方波
;**********************************
fangbo
l	movlw	.2
	movwf	count10
     
l1     	 bcf     intcon,t0if        ;将tmr0中断标志位清0
         movf    temp0,0            ;在tmr0中装入初值,开始计时
         movwf   tmr0		    ;启动定时器
l2     	 btfss   intcon,t0if        ;判断中断溢出否
         goto    l2               ;否,循环
         movlw   b'00010000'
         xorwf   portc,1             ;是,rc4引脚输出电平翻转
	 decfsz  count,1
	 goto	  l1
	 decfsz	 count10,1
	 goto	 l1
         return
;*************分频比为8的子程序(中音用)***************************
fenpin8 
        incf special,1
        incf special2,1
	bsf	status,rp0;设置文件寄存器的体1
        movlw  b'00000010';;设置分频比为1:8
        movwf  option_reg
	bcf	status,rp0;;恢复到文件寄存器的体0
        return;子程序返回
;*************分频比为16的子程序(低音用)**********************
fenpin16
        incf special,1
        incf special2,1
	bsf	status,rp0;设置文件寄存器的体1
        movlw  b'00000011';;设置分频比为1:16
        movwf  option_reg
	bcf	status,rp0;;恢复到文件寄存器的体0
        return;子程序返回
;*************分频比为4的子程序(高音用)**********************
fenpin4
        incf special,1
        incf special2,1
	bsf	status,rp0;设置文件寄存器的体1
        movlw  b'00000001';;设置分频比为1:4
        movwf  option_reg
	bcf	status,rp0;;恢复到文件寄存器的体0
        return;子程序返回
;***********************************************************
;*************** writein ***********************
writein
  incf special,1
  clrf addr;将地址变量清0,按照书上的做法
  call write;真正进入存储1,寻址2,存储
;************ e2pcom 存储子程序********************
;入口参数;yinfu寄存器中的数据写到addr寄存器指定的单元
;出口参数;是把读出的音符保存在yinfu 中
;***************************************************
write 
  clrf special2
 
  bcf status,rp1;
  bcf status,rp0;bank0
  call keyscan;调用键盘扫描子程序
  comf value,0;位置码取反送W
  btfsc status,z;测试有键按下否?有!跳过下条指令
  goto write;无!循环检测
  movlw .13;预置外循环变量
  movwf data1;以便产生10ms延时
  call delaytemp;调用延时子程序,消除接通抖动的影响
  call keyscan;再次调用键盘扫描子程序
  comf value,0;位置码取反送W
  btfsc status,z;测试有键按下否?有!跳过下条指令
  goto write;无!循环检测
  call translate;调用键值翻译子程序

  movf fsr,w;键值为“D"时,不发音
  xorlw 0dh
  btfsc status,z
  goto write

  movf fsr,w;;送键值到W-若按键为‘9’,进入读功能(间接寻址
  xorlw 09h;;与09h异或,影响状态位
  btfsc status,z;;看Z位是否为0,是!跳一步
  goto readin;;否!则调用读子程序

  movf fsr,w;“0”返回主程序
  xorlw 0h
  btfsc status,z
  goto loopmain

  movf fsr,w;高低音转换
  xorlw 0ah
  btfsc status,z
  goto fenpin4

  movf fsr,w;高低音转换
  xorlw 0bh
  btfsc status,z
  goto fenpin8


  movf fsr,w;高低音转换
  xorlw 0ch
  btfsc status,z
  goto fenpin16

  movlw 0h;;送0h到W--------由特殊操作判断寄存器是否为0判断是否为特殊操作(因为进入特殊操作时都会给special2加1)
  subwf special2,0;special2-W值送W
  btfss status,z;看Z位是否为1,是!跳一步
  goto write

  call lcdshow
  movf fsr,w;;将翻译键值送到W
  movwf yinfu;;保存在定义的寄存器中
  call checkyinch;;查表得对应音长
  movwf count;;通过W传给参数COUNT设置音长的延时
  movf yinfu,0;;将翻译键值送到W
  call checkyingao;;查表得对应音调
  movwf temp0;;通过W传给参数TEMP0设置频率
  call fangbo;;调用FANGBO子程序

;************存储标准格式
      bsf status,rp0
      bsf status,rp1 ;bank3
      btfsc eecon1,wr ;上一次写操作是否完成
      goto $-1     ;否,返回继续检测 $表示本条指令
      bcf status,rp0  ;bank2
      movf addr,w    ;取地址
      movwf eeadr    ;送地址寄存器
      movf fsr,w   ;取数据
      movwf eedata   ;送数据寄存器
      bsf status,rp0 ;bank3
      bcf eecon1,eepgd ;选定e2prom为访问对象
      bsf eecon1,wren ;开放写操作使能控制
;     bcf intcon,gie  ;禁止所有中断
      movlw 55h  ;一下是固定的
      movwf eecon2
      movlw 0aah
      movwf eecon2
      bsf eecon1,wr  ;启动写操作
      bcf eecon1,wren ;禁止写操作发生
      bcf status,rp1
      bcf status,rp0 ;bank0
      incf addr,f;地址递增
writecheck      ;检查write中按下的按键是否已经松开
      movlw .117;;预置外循环变量
      movwf data1;;以便产生100ms延时
      call delaytemp;;调用延时子程序,消除接通抖动的影响
      movlw 0f0h;;将C口高4位输出状态反转,使D7-D3闪烁
      xorwf portc,1;;以提示及时释放按键
              ;;或指明所显键值对应按键出现了粘连故障
      call keyscan;;调用键盘扫描子程序
      comf value,0;;位置码取反送W
      btfss status,z;;测试键全部释放否?是!跳过下条指令
      goto writecheck;;否,回到writecheck,循环检测
      goto write;;是,大循环
;************** readin  *********************
;入口参数:w中的键值
;**********************************
readin
 movf addr,w;;将地址变量送W
 xorlw 00h;与0比较,这一点设计要从write与read的整个循环来想
          ;如果read完成之后,没有新的write,则只能重复read
 btfss status,z
 goto read;不为0!则证明有新一次的输入,调用read
 goto read1;为0!则功能为重复播放上一次内容,调用read1,不改

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -