📄 can.c
字号:
/*****************************************************************/
/*名 称: 语音模块实验 */
/*功 能: 能够录制,播放语音信息 */
/*芯片类型: AT89S51 */
/*晶振频率: 11.0592MHZ */
/*难度等级: 高 */
/*作 者: 救火车 */
/*版 权: http://www.qm999.cn */
/*编写日期: 2008-12-5 */
/*****************************************************************/
#include <reg51.h>
#include <delay.h>
sbit SCK = P0^0; //语音模块控制管脚定义
sbit SS = P0^1;
sbit MOSI = P0^2;
sbit MISO = P0^3;
sbit INT = P0^4;
sbit RAC = P0^5;
sbit PLAY = P1^6; //录音/放音 按键
sbit STOP = P1^5; //复位按键
sbit P_R = P1^7; //录音/放音跳线
sbit KEY=P3^2; //定义按键使用的I/O口,P3.2 此处定义为KEY ,与学习板上标号保持一致。
sbit LED = P2^7; //学习板上指示灯
sbit spk=P2^5; //定义蜂鸣器使用的I/O口P2.5
#include "beep.c"
#include <intrins.h>
#include "sub4094.c"
#include "uart.c"
/*
ISD4003 SPI串行发送子程序 8位数据
*/
//向语音芯片发送数据函数
void spi_send(unsigned char isdx)
{
unsigned char i;
SS = 0;
SCK = 0;
for(i = 0;i < 8;i++) //先发低位再发高位,依次发送
{
if((isdx&0x01) == 1) MOSI = 1;
else MOSI = 0;
isdx>>=1;
SCK = 1;
delay_us(2);
SCK = 0;
delay_us(2);
}
}
void isd_stop(void) //发送STOP指令
{
delay_us(10);
spi_send(0x30);
SS = 1;
delay_ms(50);
}
void isd_pu(void) //发送上电指令,延时50ms
{
delay_us(10);
SS = 0;
spi_send(0x20);
SS = 1;
delay_ms(50);
}
void isd_pd(void) //发送掉电指令
{
delay_us(10);
spi_send(0x10);
SS = 1;
delay_ms(50);
}
void isd_play(void) //发送放音指令
{
LED=0;
spi_send(0xf0);
SS = 1;
}
void isd_rec(void) //发送录音指令
{
LED=0;
spi_send(0xb0);
SS = 1;
}
void isd_setplay(unsigned char adl,unsigned char adh) //发送放音地址指令
{
spi_send(adl); //发送放音起始低地址
adh = adh|0xe0;
spi_send(adh); //发送放音起始高地址
SS = 1;
}
void isd_setrec(unsigned char adl,unsigned char adh) //发送录音地址指令
{
spi_send(adl); //发送录音起始低地址
adh = adh|0xa0;
spi_send(adh); //发送录音起始高地址
SS = 1;
}
void isd_overflow(void) //芯片溢出警告函数
{
while(0 == PLAY) //指示灯闪烁
{
LED = 0;
delay_ms(300);
LED = 1;
delay_ms(300);
}
}
unsigned char chk_isdovf() //检测芯片溢出函数
{
SS = 0;
delay_us(2);
SCK = 0;
delay_us(2);
SCK = 1;
SCK = 0;
delay_us(2);
if (1 == MISO)
{
SCK = 0; //
SS = 1; //关闭SPI通信端
isd_stop(); //发送STOP指令
return (1); //OVF为1 返回 1
}
else
{
SCK = 0;
SS = 1; //关闭SPI通信
isd_stop(); //发送STOP指令
return (0); //OVF为0 ,返回 0
}
}
void sect_play(unsigned char adl,unsigned char adh) //放音函数
{
isd_setplay(adl,adh);
isd_play();
delay_us(20);
while(1 == INT);
LED = 1;
isd_stop();
if(chk_isdovf())
{
isd_stop();
isd_pd();
}
}
//函数名称:返回指令执行情况函数
//输入参数:命令码,帧序号,指令执行标志,
void ret_order(unsigned char order,unsigned char zhen_xh,unsigned char state)
{
unsigned char sum;
putchar(0xfa); //起始字
putchar(0x05); //字节个数
putchar(order); //命令码
sum=0x05+order;
putchar(zhen_xh); //帧序号
sum+=zhen_xh;
putchar(state); //指令执行标志 0失败,1成功
sum+=0x01;
putchar(sum); //校验码
putchar(0xfb); //结束字
}
unsigned char frame;
void main(void)
{
unsigned char i,kk; //随即变量
unsigned char LAST_KEY,THIS_KEY; // 独立按键状态变量
unsigned char order,zjgs,zhen_xh,sum; //串行通讯 命令码,字节个数,帧序号,校验码
unsigned short tt; //延时计数变量
unsigned char rx_data[10]; //串口接收 数据缓冲区
P4=0xff; //将模拟I/O口P4所有管脚置为高电平 ,对于P4,P5的定义,在sub4094.C文件中。
P5=0xff; //将模拟I/O口P5所有管脚置为高电平
update4094(); //通过对4094的操作, 控制P4,P5的输出状态。经过此操作之后,数码管和流水灯就不会显示任何东西了。
init_uart(); //初始化串行口
isd_pu(); //发送语音模块上电指令
isd_pd(); //掉电指令
isd_pu(); //上电指令
delay_ms(500);
while(1)
{
while(1 == PLAY) //等待PLAY按键被按下
{
if(0 == PLAY) delay_ms(20); //如果按键被按下,延时去抖动
if(6 > rx_counter) goto end; //如果串行口缓冲区内数据不超过6个字节。跳出
kk = getchar();
if(0xfa != kk) goto end; //如果缓冲区内第一个字节不是0XFA,跳出
zjgs = getchar(); //读取整条指令字节个数
tt=0;
while(rx_counter < zjgs) //如果缓冲区内字节数小于指令字节数
{
if(tt++ > 2000) goto end; //延时一段时间, 如果超时,退出
}
sum = zjgs; //计算校验码
order = getchar(); //读取命令码
sum+= order;
zhen_xh = getchar(); //读取帧序号
sum+= zhen_xh;
for(i = 0;i < zjgs-4;i++) //读取信息数据流
{
rx_data[i] = getchar();
sum+= rx_data[i];
}
kk = getchar(); //读取校验码
if(kk != sum) //如果校验不正确
{
ret_order(order,zhen_xh,0); //返回指令校验失败
for(i=0;i<8;i++)
{
LED=~LED; //取反指示灯
spk=~spk; //取反蜂鸣器
delay_ms(200);
}
goto end; //退出
}
kk = getchar(); //校验正确 读取结束字
if(0xfb != kk) {putchar (0);goto end;} //如果结束字不正确,退出。
switch(order) //整条指令校验正确,根据命令码进行操作。
{
case 23:
delay_ms(10);
isd_setrec(rx_data[0],rx_data[1]); //发送录音开始地址给ISD4003
isd_rec(); //发送录音指令给ISD4003
tt=rx_data[3];
tt<<=8;
tt=tt+rx_data[2];
delay_ms(tt); //延时等待录音完毕。
LED=1;
isd_stop(); //发送停止录音指令
ret_order(order,zhen_xh,1); //返回指令执行成功
break;
case 24: sect_play(rx_data[0],rx_data[1]); //放音函数
tt=rx_data[3];
tt<<=8;
tt=tt+rx_data[2];
delay_ms(tt); //延时等待放音完毕。
ret_order(order,zhen_xh,1); //返回指令执行成功
break;
case 25: isd_stop();
ret_order(order,zhen_xh,1); //返回指令执行成功
break;
default:break;
}
end:;
}
isd_pu(); //发送上电指令
isd_pd(); //发送掉电指令
isd_pu(); //发送上电指令
if(0 == P_R) //如果跳线在录音一端,进入录音状态
{
//sound_1();
delay_ms(500);
isd_setrec(0x00,0x00); //发送录音开始地址
do
{
isd_rec(); //发送录音指令
while (0 == PLAY) //循环等待录音结束
{
if (0 == INT) isd_overflow(); //如果溢出,则指示灯闪烁
}
if(0 == INT) break; //跳出
LED = 1;
isd_stop(); //发送停止录音指令
while(1 == PLAY) //等待按键被按下
{
if(0 == STOP) break; //按一下STOP键,跳出录音操作过程
if(0 == PLAY) {delay_ms(500);}
}
}while(0 == PLAY);
}
else //如果跳线在放音一端
{
//sound_1();
//delay_ms(50);
//sound_1();
while(0 == PLAY); //按一下PLAY按键,等待按键抬起,
isd_setplay(0x00,0x00); //发送放音地址,
do
{
isd_play(); //发送放音指令。
delay_us(20);
while(1 == INT) //放音,直到遇到一段语音结束标志
{
LAST_KEY=THIS_KEY;
THIS_KEY=KEY;
if((1 == LAST_KEY)&&(0 == THIS_KEY))
{
sound_1();
break;
}
}
LED = 1; //放音结束,熄灭放音指示灯
isd_stop();
if(chk_isdovf()) break;
while(1 == PLAY)
{
if(0 == STOP) break; //按一下STOP按键,结束放音过程
if(0 == PLAY) delay_ms(20);
}
}while(0 == PLAY);
}
isd_stop();
isd_pd();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -