|
程序如下!ICC编译!图片以后上!身边没相机!
程序实例:基于TWI(IIC)总线控制的TEA5767数字调频收音机实验程序
作者:刘佳杭
河北理工大学轻工学院07通信2班
日期:2009-01-19
按键功能说明:
(1)UP键,此键在正常工作模式下的作用是电台频率的上升,每次上升为100K,存储频道和读取存储频道的状态下是频道选择的上升键,每次步进1.
(2)DOWN键,作用和UP一样,只是频率的下降和频道数的下降。
(3)S/M READ键,此键的作用分为长按和短按。每次短按一次是在立体声和单声道之间切换。长按大约三秒进入存储频道读取状态,屏幕上会显示
“CH:1 READ!”,此时配合UP键和DOWN键来选择将要读取的频道,选择好后,长按此键大约三秒确认,屏幕上会显示“CH:1 OK!”,表示读取成功,此时
该频道的频率会导入PLL,立即收听此电台。
(4)SAVE键,此键的作用是存储当前电台频道到指定频道,按一次切换到次状态,屏幕上显示“”,此时配合UP键和DOWN键来选择将要存储的频道,
选择好后再次按一下此键,该频率就存入了指定选择频道,屏幕上显示“”,表示存储成功!
说明:存储频道在这里我只是设置了9个频道,存储的频道最多可以达到256个,但是太多没有多大的意义。如果想增加可自行更改程序!
没有加自动搜索功能!感觉没必要!
电路图大家线参考一下啊!这个图是我早画的!TDA2822功放部分电路有问题,大家不要参考TDA2822部分电路,等我传修改版!!新图再实验室,一会传上来!
新图纸!现在已经上传!
点击此处下载 ourdev_422507.pdf(文件大小:202K) (原文件名:TEA5767.pdf)
/*****************************************************************
程序实例:基于TWI(IIC)总线控制的TEA5767数字调频收音机实验程序
作者:刘佳杭
河北理工大学轻工学院07通信2班
日期:2009-01-19
*****************************************************************/
#include <iom16v.h>
#include <macros.h>
//头文件包含
#define uint unsigned int
#define uchar unsigned char
//数据类型宏定义
#define start 0x08
#define add_ack 0x18
#define date_ack 0x28
#define read_ack 0x50
//四个数据是为了检验每次向TWI从设备发送数据或者命令时验证是否成功,当单片机作为主机时可以省略,本程序没有采用。
#define Start() (TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)) //产生START信号
#define Stop() (TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)) //产生STOP信号
#define Wait() while(!(TWCR&(1<<TWINT))) //等待当前操作完成
#define TestACK() (TWSR&0xF8) //取出状态码
#define SetACK() (TWCR|=(1<<TWEA)) //产生ACK
#define Writebyte(twi_d) {TWDR=(twi_d);TWCR=(1<<TWINT)|(1<<TWEN);} //发送一个字节(twi_d为写入的数据)
#define tea5767_add_w 0xc0
#define tea5767_add_r 0xc1
#pragma data:data //在数据区定义以下变量和常量
uint frequency_5767=8750;//频率基准是87.5MHZ,美国欧洲中国频段
char frequen_temp1=0,frequen_temp2=0,frequen_temp3=0,frequen_temp4=0;
uchar i=0,band=0,flag=0,flag_key=0,add=1,flag_dis=0,flag_temp=0,temp_save=0;
uchar save_add=1;
uchar receive[];
uchar send[];
uint long_key=0;
uchar rx[5]={0,0,0,0,0};
uint pll;
uchar flag1=0,flag2=0,temp=0,temp1=0;
/**************************************
模块名称:延时子程序
模块功能:软件延时,在晶振为8M时,此延时子程序执行一次是1MS
**************************************/
void delay(uint x)
{
uint a,b;
for(a=110;a>0;a--)
for(b=x;b>0;b--);
}
void count_dis()
{
frequen_temp1=(frequency_5767/10)%10;
frequen_temp2=(frequency_5767/100)%10;
frequen_temp3=(frequency_5767/1000)%10;
frequen_temp4=(frequency_5767/10000)%10;
}
//功能:E2PROM单字节读函数
uchar e2prom_read(uint addr)
{
while(EECR & (1<<EEWE));
EEAR = addr;
EECR|=BIT(EERE);
return EEDR;
}
//功能:单字节写函数
void e2prom_write(uint addr,uchar wData)
{
while(EECR & BIT(EEWE));
EEAR=addr;
EEDR=wData;
EECR|=BIT(EEMWE);
EECR|=BIT(EEWE);
}
//功能:E2PROM多字节读函数
void e2prom_reads(uint addr, char *ptr, uint size)
{
uint i;
for(i=0;i<size;i++)
{
ptr=e2prom_read(addr+i);
delay(10);
}
}
//功能:E2PROM多字节读函数
void e2prom_writes(uint addr, uchar *ptr, uint size)
{
uint i;
for(i=0;i<size;i++)
{
e2prom_write(addr+i,ptr);
delay(10);
}
}
void save_channel()
{
send[0]=(uchar)(frequency_5767/256);
send[1]=frequency_5767&0x00ff;
e2prom_writes(add,send,2);
delay(30);
}
void calculate_pll(unsigned long temp)
{
pll = (unsigned int)(((temp*10-225)*4000)/32768);
}
/*********向1602液晶写指令**********/
void write_com(uchar com)
{
PORTA&=0xbf;//rs清0,写指令
PORTB = (PORTB & 0x0f)|com;//写指令,送高四位
PORTA|=0x80;//en置位
PORTA&=0x7f;//en清0
PORTA&=0xbf;//rs清0,写指令
PORTB = (PORTB & 0x0f)|(com<<4);//写指令,送高四位
PORTA|=0x80;//en置位
PORTA&=0x7f;//en清0
}
/*********向1602液晶写数据**********/
void write_dat(uchar dat)
{
PORTA|=0x40;//rs置位,写数据
PORTB = (PORTB & 0x0f)|dat;//写数据,送低四位
PORTA|=0x80;
PORTA&=0x7f;
PORTA|=0x40;//rs置位,写数据
PORTB = (PORTB & 0x0f)|(dat<<4);//写数据,送低四位
PORTA|=0x80;
PORTA&=0x7f;
}
/*********1602液晶初始化**********/
void init_1602()
{
PORTA&=0x7f; //EN清0
write_com(0X33);//
delay(5);
write_com(0X32);//先设置为八位模式,然后再设置为4线模式,否则显示出问题!!!!!!!
delay(5);
write_com(0X28);//4位数据,16*2两行显示,5*7显示
delay(5);
write_com(0X0c);//
delay(5);
write_com(0X06);//自动移位
delay(5);
write_com(0X01);//自动移位
delay(5);
}
void send_cgram(uchar len,uchar cgram_add)
{
uchar k;
write_com(cgram_add);
for(k=0;k<len;k++)
{
//write_dat(table[k]);
}
}
/*******************************************
函数名称: LCD1602_gotoXY
功 能: 移动到指定位置
参 数: Row--指定的行
Col--指定的列
返回值 : 无
/********************************************/
void LCD1602_gotoXY(uchar Row,uchar Col)
{
switch (Row) //选择行
{
case 1:
write_com(0x80+Col); break; //写入第1行的指定列
default:
write_com(0x80+0x40+Col); break; //写入第1行的指定列
}
}
void LCD1602_disCGRAM(void)
{
uchar i;
LCD1602_gotoXY(1,6); //从第1行第6列开始显示
for (i = 0;i <4;i++) //显示前32个字节的内容
{
write_dat(i);
}
LCD1602_gotoXY(2,6); //从第2行第6列开始显示
for (i = 4;i <8;i++) //显示后32个字节的内容
{
write_dat(i);
}
}
/*******************************************
函数名称: LCD1602_sendstr
功 能: 向1602液晶写入一个字符串
参 数: ptString--字符串指针
返回值 : 无
/********************************************/
void LCD1602_sendstr(uchar *ptString)
{
while((*ptString)!='\0') //字符串未结束就一直写
{
write_dat(*(ptString++));
delay(0);
}
}
void display(uchar hang,uchar lie,uchar *str)
{
LCD1602_gotoXY(hang,lie);
LCD1602_sendstr(str);
}
void display_one(uchar hang,uchar lie,uchar wor)
{
LCD1602_gotoXY(hang,lie);
write_dat(wor);
}
/**************************************
模块名称:TWI总线初始化
模块功能:配置TWI总线,使之工作方式与tea5767相兼容。
**************************************/
void init_twi()
{
TWCR=0X00; //关闭TWI总线
TWBR=0x12; //设置传输比特率
TWSR=0x03; //设置TWI总线的速度,频率不能大于400K,否则5767不工作
TWCR=0x04; //使能TWI总线
}
/**************************************
模块名称:TWI读取从设备数据程序(从5767读取温度值程序)
模块功能:读取5767
**************************************/
uchar read_byte()
{
uchar i;
TWCR|=0x04;
Wait();
i=TWDR;
return i;
}
void read_5767(uchar data)
{
uchar k;
Start();
Wait();
Writebyte(tea5767_add_r);
Wait();
for(k=0;k<5;k++)
{
rx[k]=read_byte();
}
}
void write_5767(uint tx0,uint tx1,uchar tx2,uchar tx3,uchar tx4)
{
Start();
Wait();
Writebyte(tea5767_add_w);
Wait();
Writebyte(tx0);
Wait();
Writebyte(tx1);
Wait();
Writebyte(tx2);
Wait();
Writebyte(tx3);
Wait();
Writebyte(tx4);
Wait();
Stop();
}
void read_channel()
{
e2prom_reads(add,receive,2);
frequency_5767=(uint)receive[0]*256+receive[1];
//frequency_5767=((int)receive[0]<<8)|receive[1];
calculate_pll(frequency_5767);
count_dis();
write_5767(pll/256,pll%256,0x01|band,0x90,0x00);
display_one(2,9,frequen_temp1+0x30);
display_one(2,7,frequen_temp2+0x30);
display_one(2,6,frequen_temp3+0x30);
if(frequen_temp3==0)
flag_dis=0;
else
flag_dis=1;
if(flag_dis==0)
display_one(2,5,frequen_temp4+0x30);
else
display(2,5," ");
}
void init_5767()
{
calculate_pll(frequency_5767);
write_5767(pll/256,pll%256,0x01,0x90,0x00);// 初始化为:不再搜索模式,
}
void init_sys()
{
DDRD&=0x0f;
PORTD|=0XF0;//上拉电阻使能
DDRB=0XFF;//设置PORTB口数据方向为输出
DDRA|=0xc0;//设置PORTD口PORTA7和PORTA6为输出
DDRC|=0X01;
}
uchar scan_press()
{
i=PIND&0xf0;
if(i==0xf0)
return 0;
else
return 1;
}
uchar key_scan()
{
uchar value_key=0;
if(scan_press()==1)
{
delay(8);
switch (i)
{
case 0xf0:
break;
case 0x70:
value_key=1;
delay(30);
break;
case 0xb0:
value_key=2;
delay(30);
break;
case 0xd0:
while((PIND&0XF0)==0Xd0)
{
long_key++;
delay(2);
}
value_key=3;
delay(30);
break;
case 0xe0:
while((PIND&0XF0)==0XE0);
delay(5);
value_key=4;
delay(30);
break;
default:
value_key=0;
delay(30);
break;
}
}
return value_key;
}
void key()
{
scan_press();
key_scan();
}
void min_control()
{
if(frequen_temp1==-1)
{
frequen_temp1=9;
frequen_temp2--;
}
if(frequen_temp2==-1)
{
frequen_temp2=9;
frequen_temp3--;
}
if(frequen_temp3==-1)
{
frequen_temp3=9;
frequen_temp4--;
}
}
void add_control()
{
if(frequen_temp1==10)
{
frequen_temp1=0;
frequen_temp2++;
}
if(frequen_temp2==10)
{
frequen_temp2=0;
frequen_temp3++;
}
if(frequen_temp3==10)
{
frequen_temp3=0;
frequen_temp4++;
}
}
void control_tea5767()
{
uchar k=0;
k=key_scan();
if(k!=0)
{
switch (k)
{
case 1:
if(flag_key==0)
{
flag2=0;
if(flag1==0)
frequency_5767=frequency_5767+10;
count_dis();
add_control();
if((frequen_temp3==0)&&(frequen_temp2==8)&&(frequen_temp1==0))
flag1=1;
if(frequen_temp3==0)
flag_dis=0;
else
flag_dis=1;
display_one(2,9,frequen_temp1+0x30);
display_one(2,7,frequen_temp2+0x30);
display_one(2,6,frequen_temp3+0x30);
if(flag_dis==0)
display_one(2,5,frequen_temp4+0x30);
else
display(2,5," ");
calculate_pll(frequency_5767);
write_5767(pll/256,pll%256,0x01|band,0x90,0x00);
}
else
{
while((PIND&0XF0)==0X70);
delay(50);
save_add++;
if(save_add>0)
{
if(save_add==1)
add=1;
if(save_add==2)
add=3;
if(save_add==3)
add=5;
if(save_add==4)
add=7;
if(save_add==5)
add=9;
if(save_add==6)
add=11;
if(save_add==7)
add=13;
if(save_add==8)
add=15;
if(save_add==9)
add=17;
if(save_add==10)
save_add=1;
display(1,5,"CH:");
display_one(1,8,save_add+0x30);
}
}
break;//增加频率
case 2:
if(flag_key==0)
{
flag1=0;
if(flag2==0)
frequency_5767=frequency_5767-10;
count_dis();
min_control();
if((frequen_temp4==0)&&(frequen_temp3==8)&&(frequen_temp2==7)&&(frequen_temp1==5))
flag2=1;
if(frequen_temp4!=1)
flag_dis=1;
else flag_dis=0;
if(frequen_temp3==0)
flag_dis=0;
display_one(2,9,frequen_temp1+0x30);
display_one(2,7,frequen_temp2+0x30);
display_one(2,6,frequen_temp3+0x30);
if(flag_dis==0)
display_one(2,5,frequen_temp4+0x30);
else
display(2,5," ");
if((frequen_temp3==9)&&(frequen_temp2==9))
flag_dis=1;//此位是为了消除高位的0,使得显示明了
calculate_pll(frequency_5767);
write_5767(pll/256,pll%256,0x01|band,0x90,0x00);
}
else
{
if(save_add>0)
{
while((PIND&0XF0)==0Xb0);
delay(50);
save_add--;
if(save_add==1)
add=1;
if(save_add==2)
add=3;
if(save_add==3)
add=5;
if(save_add==4)
add=7;
if(save_add==5)
add=9;
if(save_add==6)
add=11;
if(save_add==7)
add=13;
if(save_add==8)
add=15;
if(save_add==9)
add=17;
if(save_add==0)
save_add=9;
display(1,5,"CH:");
display_one(1,8,save_add+0x30);
}
else
save_add=1;
}
break;//减小频率
case 3:
if(long_key>500)
{
display(1,5,"CH:");
display_one(1,8,save_add+0x30);
long_key=0;
temp_save=temp_save+1;
flag_temp=1;
flag_key=1;
temp=0;
}
else
{
flag_temp=0;//flag_temp用于控制单声道和立体声的切换,如果不执行就执行存储频道的读取
flag_key=0;
long_key=0;
}
if(temp_save!=0)
{
if(temp_save==1)
{
flag_key=1;
flag_temp=1;
display(1,10," READ!");
display(1,5,"CH:");
display_one(1,8,save_add+0x30);
}
if(temp_save==2)
{
flag_temp=1;
flag_key=0;
display(1,10," OK!");
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////frequency_5767=EEPROMread(add);//读取频道频率
read_channel();
delay(3000);
display(1,5," ");
display(1,10,"Stereo");
}
if(temp_save==2)
temp_save=0;
}
if(flag_temp==0)
temp++;
if(temp==1)//3-0xa1
{
display(1,10," Mono");
band=0x08;
write_5767(pll/256,pll%256,0x01|band,0x90,0x00);
}//单声道
if(temp==2)//3-0xa9
{
display(1,10,"Stereo");
band=0x00;
write_5767(pll/256,pll%256,0x01|band,0x90,0x00);
}//立体声
if(temp==2)
temp=0;
break;//立体声和单声道切换.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
case 4:
temp1++;
if(temp1==1)
{
display(1,5,"CH:");
display_one(1,8,save_add+0x30);
flag=1;
flag_key=1;
}
if(temp1==2)
{
flag=1;
flag_key=0;
display(1,10,"Saved!");
save_channel();//////////////////////////////////////////EEPROMwrite(add,frequency_5767);
delay(2000);
display(1,10,"Stereo");
display(1,5," ");
}
if(temp1==2)
{
temp1=0;
}
break;//存储频道
default:
break;
}
}
}
void dispaly_init()
{
count_dis();
display(1,2,"Designed by");
display(2,2,"Liu Jiahang");
delay(5000);
write_com(0x01);
delay(10);
display(1,0,"Based On IIC-BUS");
display(2,0,"TEA5767 FM TURNR");
delay(5000);
write_com(0x01);
delay(10);
display(1,3,"Starting...");
display(2,1,"Please Waiting!");
delay(3000);
write_com(0x01);
delay(10);
display(1,10,"Stereo");
display(2,1,"FM:");
display(2,4," 87.5 MHZ");
}
/*********主函数**********/
void main()
{
uchar i;//设置循环变量I
init_sys();
init_1602();
init_twi();
init_5767();
dispaly_init();
while(1)
{
key();
control_tea5767();
}
} |
阿莫论坛20周年了!感谢大家的支持与爱护!!
一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。
|