基于51单片机语音模块(录音放音功能)

效果图:

 

淘宝网址:http://item.taobao.com/item.htm?id=15953525846

程序:

 

  
  
  
  
  1. #include <reg52.h>  
  2. #include <intrins.h>  
  3. #define uchar unsigned char  
  4. #define uint  unsigned int  
  5. //录音和放音键IO口定义:  
  6. sbit   AN=P2^6;//放音键控制接口  
  7. sbit    set_key=P2^7;//录音键控制口  
  8. // ISD4004控制口定义:  
  9. sbit SS  =P1^0;     //4004片选  
  10. sbit MOSI=P1^1;     //4004数据输入  
  11. sbit MISO=P1^2;     //4004数据输出  
  12. sbit SCLK=P1^3;     //ISD4004时钟  
  13. sbit INT =P1^4;     //4004中断  
  14. sbit STOP=P3^4;     //4004复位  
  15. sbit LED1 =P1^6;    //录音指示灯  
  16. //===============================LCD1602接口定义=====================  
  17. /*-----------------------------------------------------  
  18.        |DB0-----P2.0 | DB4-----P2.4 | RW-------P0.1    |  
  19.        |DB1-----P2.1 | DB5-----P2.5 | RS-------P0.2    |  
  20.        |DB2-----P2.2 | DB6-----P2.6 | E--------P0.0    |  
  21.        |DB3-----P2.3 | DB7-----P2.7 | 注意,P0.0到P0.2需要接上拉电阻  
  22.     ---------------------------------------------------  
  23. =============================================================*/ 
  24. #define LCM_Data     P0    //LCD1602数据接口  
  25. sbit    LCM_RW     = P2^3;  //读写控制输入端,LCD1602的第五脚  
  26. sbit    LCM_RS     = P2^4;  //寄存器选择输入端,LCD1602的第四脚  
  27. sbit    LCM_E      = P2^2;  //使能信号输入端,LCD1602的第6脚  
  28. //***************函数声明************************************************  
  29. void    WriteDataLCM(uchar WDLCM);//LCD模块写数据  
  30. void    WriteCommandLCM(uchar WCLCM,BuysC); //LCD模块写指令  
  31. uchar   ReadStatusLCM(void);//读LCD模块的忙标  
  32. void    DisplayOneChar(uchar X,uchar Y,uchar ASCII);//在第X+1行的第Y+1位置显示一个字符  
  33. void    LCMInit(void);  
  34. void    DelayUs(uint us); //微妙延时程序  
  35. void    DelayMs(uint Ms);//毫秒延时程序  
  36. void    init_t0();//定时器0初始化函数  
  37. void    setkey_treat(void);//录音键处理程序  
  38. void    upkey_treat(void);//播放键处理程序  
  39. void    display();//显示处理程序  
  40. void    isd_setrec(uchar adl,uchar adh);//发送setrec指令  
  41. void    isd_rec();//发送rec指令  
  42. void    isd_stop();//stop指令(停止当前操作)  
  43. void    isd_powerup();//发送上电指令  
  44. void    isd_stopwrdn();//发送掉电指令  
  45. void    isd_send(uchar isdx);//spi串行发送子程序,8位数据  
  46. void    isd_setplay(uchar adl,uchar adh);  
  47. void    isd_play();  
  48. //程序中的一些常量定义  
  49. uint    time_total,st_add,end_add=0;  
  50. uint    adds[25];//25段语音的起始地址暂存  
  51. uint    adde[25];//25段语音的结束地址暂时  
  52. uchar   t0_crycle,count,count_flag,flag2,flag3,flag4;  
  53. uchar   second_count=170,msecond_count=0;  
  54. //second_count为芯片录音的起始地址,起始地址本来是A0,也就是160,  
  55. //我们从170开始录音吧。  
  56. #define Busy         0x80   //用于检测LCM状态字中的Busy标识  
  57.  
  58. /*===========================================================================  
  59.  主程序  
  60. =============================================================================*/  
  61. void main(void)  
  62. {  
  63.    LED1=0;//灭录音指示灯  
  64.    flag3=0;  
  65.    flag4=0;  
  66.    time_total=340;//录音地址从170开始,对应的单片机开始计时的时间就是340*0.1秒  
  67.    adds[0]=170;  
  68.    count=0;  
  69.    LCMInit();        //1602初始化  
  70.    init_t0();//定时器初始化  
  71.    DisplayOneChar( 0,5,'I'); //开机时显示000  ISD4004-X  
  72.    DisplayOneChar( 0,6,'S');  
  73.    DisplayOneChar( 0,7,'D');  
  74.    DisplayOneChar( 0,8,'4');  
  75.    DisplayOneChar( 0,9,'0');  
  76.    DisplayOneChar( 0,10,'0');  
  77.    DisplayOneChar( 0,11,'4');  
  78.    DisplayOneChar( 0,12,'-');  
  79.    DisplayOneChar( 0,13,'X');  
  80.    while(1)  
  81.    {  
  82.       display();//显示处理  
  83.       upkey_treat();//放音键处理  
  84.       setkey_treat();//录音键处理  
  85.    }  
  86. }  
  87. //*******************************************  
  88. //录音键处理程序  
  89. //从指定地址开始录音的程序就是在这段里面  
  90. void setkey_treat(void)  
  91. {  
  92.    set_key=1;//置IO口为1,准备读入数据  
  93.    DelayUs(1);  
  94.    if(set_key==0)  
  95.    {  
  96.       if(flag3==0)//录音键和放音键互锁,录音好后,禁止再次录音。如果要再次录音,那就要复位单片机,重新开始录音  
  97.       {  
  98.         if(count==0)//判断是否为上电或复位以来第一次按录音键  
  99.         {  
  100.            st_add=170;  
  101.         }  
  102.         else 
  103.         {  
  104.           st_add=end_add+3;   
  105.         }//每段语言间隔3个地址  
  106.         adds[count]=st_add;//每段语音的起始地址暂时  
  107.         if(count>=25)//判断语音段数时候超过25段,因为单片机内存的关系?  
  108.        //本程序只录音25段,如果要录更多的语音,改为不可查询的即可  
  109.         {//如果超过25段,则覆盖之前的语音,从新开始录音  
  110.            count=0;  
  111.            st_add=170;  
  112.            time_total=340;  
  113.         }  
  114.         isd_powerup(); //AN键按下,ISD上电并延迟50ms  
  115.         isd_stopwrdn();  
  116.         isd_powerup();   
  117.         LED1=1;//录音指示灯亮,表示录音模式  
  118.         isd_setrec(st_add&0x00ff,st_add>>8); //从指定的地址  
  119.         if(INT==1)// 判定芯片有没有溢出  
  120.         {         
  121.             isd_rec(); //发送录音指令  
  122.         }  
  123.         time_total=st_add*2;//计时初始值计算  
  124.         TR0=1;//开计时器  
  125.         while(set_key==0);//等待本次录音结束  
  126.         TR0=0;//录音结束后停止计时  
  127.         isd_stop(); //发送4004停止命令  
  128.         end_add=time_total/2+2;//计算语音的结束地址  
  129.         adde[count]=end_add;//本段语音结束地址暂存  
  130.         LED1=0; //录音完毕,LED熄灭  
  131.         count++;//录音段数自加  
  132.         count_flag=count;//录音段数寄存  
  133.         flag2=1;  
  134.         flag4=1;//解锁放音键  
  135.       }  
  136.   }  
  137. }  
  138. //=================================================  
  139. //放音机处理程序  
  140. //从指定地址开始放本段语音就是这段程序  
  141. void upkey_treat(void)  
  142. {  
  143.    uchar ovflog;  
  144.    AN=1;//准备读入数据  
  145.    DelayUs(1);  
  146.    if(AN==0)//判断放音键是否动作  
  147.    {  
  148.  //    if(flag4==1)//互锁录音键  
  149.  //    {  
  150.         if(flag2==1)//判断是否为录音好后的第一次放音  
  151.         {  
  152.            count=0;//从第0段开始播放  
  153.         }  
  154.         isd_powerup(); //AN键按下,ISD上电并延迟50ms  
  155.         isd_stopwrdn();  
  156.         isd_powerup();   
  157.         //170 184 196 211  
  158.    //     st_add=adds[count];//送当前语音的起始地址  
  159.         st_add=211;//送当前语音的起始地址  
  160.         isd_setplay(st_add&0x00ff,st_add>>8); //发送setplay指令,从指定地址开始放音  
  161.         isd_play(); //发送放音指令  
  162.         DelayUs(20);  
  163.         while(INT==1); //等待放音完毕的EOM中断信号  
  164.         isd_stop(); //放音完毕,发送stop指令  
  165.         while(AN==0); //   
  166.         isd_stop();  
  167.         count++;//语音段数自加  
  168.         flag2=0;  
  169.         flag3=1;  
  170.         if(count>=count_flag)//如果播放到最后一段后还按加键,则从第一段重新播放  
  171.         {  
  172.              count=0;  
  173.         }  
  174.        
  175.  //     }  
  176.    }   
  177. }  
  178. //************************************************?  
  179. //发送rec指令  
  180. void isd_rec()  
  181. {  
  182.     isd_send(0xb0);  
  183.     SS=1;  
  184. }  
  185. //****************************************  
  186. //发送setrec指令  
  187. void isd_setrec(unsigned char adl,unsigned char adh)  
  188. {  
  189.     DelayMs(1);  
  190.     isd_send(adl); //发送放音起始地址低位  
  191.     DelayUs(2);  
  192.     isd_send(adh); //发送放音起始地址高位  
  193.     DelayUs(2);  
  194.     isd_send(0xa0); //发送setplay指令字节  
  195.     SS=1;  
  196. }  
  197. //=============================================================================  
  198. //**********************************************  
  199. //定时器0中断程序  
  200. void timer0() interrupt 1  
  201. {  
  202.     TH0=(65536-50000)/256;  
  203.     TL0=(65536-50000)%256;  
  204.     t0_crycle++;  
  205.     if(t0_crycle==2)// 0.1秒  
  206.     {  
  207.       t0_crycle=0;  
  208.       time_total++;  
  209.       msecond_count++;  
  210.       if(msecond_count==10)//1秒  
  211.       {   
  212.         msecond_count=0;  
  213.         second_count++;  
  214.         if(second_count==60)  
  215.         {  
  216.           second_count=0;  
  217.         }  
  218.       }  
  219.       if(time_total==4800)time_total=0;      
  220.     }  
  221. }  
  222. //********************************************************************************************  
  223. //定时器0初始化函数  
  224. void init_t0()  
  225. {  
  226.     TMOD=0x01;//设定定时器工作方式1,定时器定时50毫秒  
  227.     TH0=(65536-50000)/256;  
  228.     TL0=(65536-50000)%256;  
  229.     EA=1;//开总中断  
  230.     ET0=1;//允许定时器0中断  
  231.     t0_crycle=0;//定时器中断次数计数单元  
  232. }  
  233. //******************************************  
  234. //显示处理程序  
  235. void display()  
  236. {  
  237.         uchar x;  
  238.         if(flag3==1||flag4==1)//判断是否有录音过或者放音过  
  239.         {  
  240.           x=count-1;  
  241.           if(x==255){x=count_flag-1;}  
  242.         }  
  243.         DisplayOneChar( 0,0,x/100+0x30);    //显示当前语音是第几段  
  244.         DisplayOneChar( 0,1,x/10%10+0x30);  
  245.         DisplayOneChar( 0,2,x%10+0x30);  
  246.         if(flag3==0)//录音时显示本段语音的起始和结束地址  
  247.         {  
  248.            DisplayOneChar( 1,0,st_add/1000+0x30);//计算并显示千位     
  249.            DisplayOneChar( 1,1,st_add/100%10+0x30);  
  250.            DisplayOneChar( 1,2,st_add/10%10+0x30);  
  251.            DisplayOneChar( 1,3,st_add%10+0x30);  
  252.            DisplayOneChar( 1,4,'-');  
  253.            DisplayOneChar( 1,5,'-');  
  254.            DisplayOneChar( 1,6,end_add/1000+0x30);     
  255.            DisplayOneChar( 1,7,end_add/100%10+0x30);  
  256.            DisplayOneChar( 1,8,end_add/10%10+0x30);  
  257.            DisplayOneChar( 1,9,end_add%10+0x30);  
  258.         }  
  259.         if(flag4==1)//放音时显示本段语音的起始和结束地址  
  260.         {  
  261.            DisplayOneChar( 1,0,adds[x]/1000+0x30);     
  262.            DisplayOneChar( 1,1,adds[x]/100%10+0x30);  
  263.            DisplayOneChar( 1,2,adds[x]/10%10+0x30);  
  264.            DisplayOneChar( 1,3,adds[x]%10+0x30);  
  265.            DisplayOneChar( 1,4,'-');  
  266.            DisplayOneChar( 1,5,'-');  
  267.            DisplayOneChar( 1,6,adde[x]/1000+0x30);     
  268.            DisplayOneChar( 1,7,adde[x]/100%10+0x30);  
  269.            DisplayOneChar( 1,8,adde[x]/10%10+0x30);  
  270.            DisplayOneChar( 1,9,adde[x]%10+0x30);  
  271.         }  
  272. }  
  273. //======================================================================  
  274. // LCM初始化  
  275. //======================================================================  
  276. void LCMInit(void)   
  277. {  
  278.  LCM_Data = 0;  
  279.  WriteCommandLCM(0x38,0); //三次显示模式设置,不检测忙信号  
  280.  DelayMs(5);  
  281.  WriteCommandLCM(0x38,0);  
  282.  DelayMs(5);  
  283.  WriteCommandLCM(0x38,0);  
  284.  DelayMs(5);  
  285.  WriteCommandLCM(0x38,1); //显示模式设置,开始要求每次检测忙信号  
  286.  WriteCommandLCM(0x08,1); //关闭显示  
  287.  WriteCommandLCM(0x01,1); //显示清屏  
  288.  WriteCommandLCM(0x06,1); // 显示光标移动设置  
  289.  WriteCommandLCM(0x0C,1); // 显示开及光标设置  
  290.  DelayMs(100);  
  291. }  
  292. //*=====================================================================  
  293. // 写数据函数: E =高脉冲 RS=1 RW=0  
  294. //======================================================================  
  295. void WriteDataLCM(uchar WDLCM)  
  296. {  
  297.  ReadStatusLCM(); //检测忙  
  298.  LCM_Data = WDLCM;  
  299.  LCM_RS = 1;  
  300.  LCM_RW = 0;  
  301.  LCM_E = 0; //若晶振速度太高可以在这后加小的延时  
  302.  LCM_E = 0; //延时  
  303.  LCM_E = 1;  
  304. }  
  305. //*====================================================================  
  306.  // 写指令函数: E=高脉冲 RS=0 RW=0  
  307. //======================================================================  
  308. void WriteCommandLCM(unsigned char WCLCM,BuysC) //BuysC为0时忽略忙检测  
  309. {  
  310.  if (BuysC) ReadStatusLCM(); //根据需要检测忙  
  311.  LCM_Data = WCLCM;  
  312.  LCM_RS = 0;  
  313.  LCM_RW = 0;  
  314.  LCM_E = 0;  
  315.  LCM_E = 0;  
  316.  LCM_E = 1;  
  317. }  
  318. //*====================================================================  
  319. //  正常读写操作之前必须检测LCD控制器状态:E=1 RS=0 RW=1;  
  320. //  DB7: 0 LCD控制器空闲,1 LCD控制器忙。  
  321.  // 读状态  
  322. //======================================================================  
  323. unsigned char ReadStatusLCM(void)  
  324. {  
  325.  LCM_Data = 0xFF;  
  326.  LCM_RS = 0;  
  327.  LCM_RW = 1;  
  328.  LCM_E = 0;  
  329.  LCM_E = 0;  
  330.  LCM_E = 1;  
  331.  while (LCM_Data & Busy); //检测忙信号    
  332.  return(LCM_Data);  
  333. }  
  334. //======================================================================  
  335. //功 能:     在1602 指定位置显示一个字符:第一行位置0~15,第二行16~31  
  336. //说 明:     第 X 行,第 y 列  注意:字符串不能长于16个字符  
  337. //======================================================================  
  338. void DisplayOneChar( unsigned char X, unsigned char Y, unsigned char ASCII)  
  339. {  
  340.  X &= 0x1;  
  341.  Y &= 0xF; //限制Y不能大于15,X不能大于1  
  342.  if (X) Y |= 0x40; //当要显示第二行时地址码+0x40;  
  343.  Y |= 0x80; // 算出指令码  
  344.  WriteCommandLCM(Y, 0); //这里不检测忙信号,发送地址码  
  345.  WriteDataLCM(ASCII);  
  346. }  
  347. //======================================================================  
  348. //spi串行发送子程序,8位数据  
  349. void isd_send(uchar isdx)  
  350. {  
  351.     uchar isx_counter;  
  352.     SS=0;//ss=0,打开spi通信端  
  353.     SCLK=0;  
  354.     for(isx_counter=0;isx_counter<8;isx_counter++)//先发低位再发高位,依次发送。  
  355.     {  
  356.         if((isdx&0x01)==1)  
  357.             MOSI=1;  
  358.         else 
  359.             MOSI=0;  
  360.             isdx=isdx>>1;  
  361.             SCLK=1;  
  362.             DelayUs(2);  
  363.             SCLK=0;  
  364.             DelayUs(2);  
  365.     }  
  366. }  
  367. //======================================================================  
  368. //stop指令(停止当前操作)  
  369. void isd_stop()//  
  370. {  
  371.     DelayUs(10);  
  372.     isd_send(0x30);  
  373.     SS=1;  
  374.     DelayMs(50);  
  375. }  
  376. //======================================================================  
  377. //发送上电指令  
  378. void isd_powerup()//  
  379. {  
  380.     DelayUs(10);  
  381.     SS=0;  
  382.     isd_send(0x20);  
  383.     SS=1;  
  384.     DelayMs(50);  
  385. }  
  386. //======================================================================  
  387. //发送掉电指令  
  388. void isd_stopwrdn()//  
  389. {  
  390.     DelayUs(10);  
  391.     isd_send(0x10);  
  392.     SS=1;  
  393.     DelayMs(50);  
  394. }  
  395.  
  396. void isd_play()//发送play指令  
  397. {  
  398.     isd_send(0xf0);  
  399.     SS=1;  
  400. }  
  401. void isd_setplay(uchar adl,uchar adh)//发送setplay指令  
  402. {  
  403.     DelayMs(1);  
  404.     isd_send(adl); //发送放音起始地址低位  
  405.     DelayUs(2);  
  406.     isd_send(adh); //发送放音起始地址高位  
  407.     DelayUs(2);  
  408.     isd_send(0xe0); //发送setplay指令字节  
  409.     SS=1;  
  410. }  
  411. void DelayUs(uint us)  
  412. {  
  413.     while(us--);  
  414. }   
  415. //====================================================================  
  416. // 设定延时时间:x*1ms  
  417. //====================================================================  
  418. void DelayMs(uint Ms)  
  419. {  
  420.   uint i,TempCyc;  
  421.   for(i=0;i<Ms;i++)  
  422.   {  
  423.     TempCyc = 250;  
  424.     while(TempCyc--);  
  425.   }  
  426. }  
  427.  

 

你可能感兴趣的:(录音模块,语音模块)