搜索
bottom↓
回复: 38

也来一个简易FM收音机,,,祝各位春节愉快!

[复制链接]

出0入0汤圆

发表于 2010-2-12 00:13:48 | 显示全部楼层 |阅读模式
之所以简易:
1,只用8个LED显示频道号2进代码,
2,因为FM只是本地广播,故需要根据当地频点编程时写入,也用不着搜索,只是针对固定频点收听
3,使用RDA5807,可以使用TEA5767也可以使用5807模式编程
4,RDA自带耳机输出和电子音量,省掉了相关电路和元件
电路示意:M8人人明白,就不啰嗦,默认内部1MHZ.5807模块也就是10个脚,只用到7个,按说它内部有50K上拉电阻供TWI,不过还是加了20K外部上拉,注意耳机地线通过高频LC入地,兼做收音天线用。

(原文件名:SIMP_FM.JPG)
可见简易至极,电源5V就取自电脑USB。
程序:由两个.C文件构成:
1:radiotwi.c:

#include <util/twi.h>
#include <util/delay.h>
/////////以下书上都有,不用解释吧//////////////////////
#define TWI_START  TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
#define TWI_STOP   TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
#define TWI_WAIT   {while(!(TWCR&(1<<TWINT)));}
#define TWI_TEST_ACK TWSR&0XF8
#define TWI_SEND_ACK  TWCR|=(1<<TWEA)
#define TWI_SEND_BYTE(X) {TWDR=(X);TWCR=(1<<TWINT)|(1<<TWEN);}

#define uchar unsigned char
#define uint unsigned int


void twi_ini()
{
    TWCR=0X00; //关闭TWI总线
    TWBR=0x11; //设置传输比特率  
    TWSR=0;    //设置TWI总线的速度,
    TWCR=0x04; //使能TWI总线
}
////////////写5807寄存器,它的02,03,04,05寄存器决定了收音机控制,函数参数是寄存器地址-控制字
uchar wri_5807(uchar r_adr,uint rx)
{
        uchar rxh,rxl;  //////////字分解为字节,TWI只能字节传送
        rxl=rx;
        rx>>=8;
        rxh=rx;
       
        TWI_START;
        TWI_WAIT;                  //等待START发出:正在发时TWINT为0,傻等他发好了TWINT为1
        TWI_TEST_ACK;
        if((TWI_TEST_ACK)!=0x08)
        {return 1;
        }
        TWI_SEND_BYTE(0X22);       //再次置位这两个,就是开始发出写,5807器件地址0X22
          TWI_WAIT;                  //等待START发出:正在发时TWINT为0,发好了TWINT为1;      
          if((TWI_TEST_ACK)!=0X18)   //非正确返回值出错
        {return 1;}
        TWI_SEND_BYTE(r_adr);      //写寄存器地址
        TWI_WAIT;          ;       //等待发送完成及给出应答信号
          if((TWI_TEST_ACK)!=0X28)
        {return 1;}
        TWI_SEND_BYTE(rxh);        //写高字节
        TWI_WAIT;                  //等待数据发送完成及给出应答信号
          if((TWI_TEST_ACK)!=0X28)
        {return 1;}
        TWI_SEND_BYTE(rxl);        //写低字节
        TWI_WAIT;                  //等待数据发送完成及给出应答信号
          if((TWI_TEST_ACK)!=0X28)
        {return 1;}
       
        TWI_STOP;
        ;

}
//////////////读5807寄存器,只有0A,0B,反映收音机状态,例如频道号码等等,函数参数就是0X0A或0X0B
uint read_5807(uchar r_adr)
{
        uint read_rab;
        uchar rabh,rabl;
        TWI_START;
        TWI_WAIT;                  //等待START发出:正在发时TWINT为0,发好了TWINT为1
       
        if((TWSR&0XF8)!=0x08)
        return 1;
       
        TWI_SEND_BYTE(0X22);       //发出写,5807器件地址0X22
          TWI_WAIT;                  
          if((TWSR&0XF8)!=0X18)
        return 1;

        TWI_SEND_BYTE(r_adr);       //发出写,寄存器地址0X0A或0X0B
          TWI_WAIT;                        
          if((TWSR&0XF8)!=0X28)
        return 1;

        TWI_START;                  //再启动
        TWI_WAIT;                  
        if((TWSR&0XF8)!=0x10)
        return 1;

        TWI_SEND_BYTE(0X23);       //读5807器件地址0X23
          TWI_WAIT;                  
          if((TWSR&0XF8)!=0X40)
        return 1;

        TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWEA);//接收数据后M8发出应答:1<<TWEA
        TWI_WAIT;
        if((TWSR&0XF8)!=0X50)
        return 1;

        rabh=TWDR;                         //读出寄存器高字节
        TWCR&=~(1<<TWEA);
        TWCR=(1<<TWINT)|(1<<TWEN);

        TWI_WAIT;
        if((TWSR&0XF8)!=0X58)
        return 1;

        rabl=TWDR;                          //读出寄存器低字节
        TWI_STOP;
        return 1;

        read_rab=0;
         read_rab+=rabh;
         read_rab<<=8;
         read_rab+=rabl;
        return read_rab;                    //返回状态字
///////////////////////////////////////////////////////////
/////////下面是主程序avrfmradio.c//////////////////////////

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>

#define uint unsigned int
#define uchar unsigned char

uchar keyscan_t=0;     ////////定时器中断标志,用来定时判断按键:状态机法
uchar dispdata=0;      ////////显示缓冲
uchar keyno;           ////////按键码
//////////////////////下面数组是本地电台频道表,0就是87MHZ,100KHZ步进,4就是87.4MHZ,依此类推
uchar tune_tab[26]={0,0x04,0x0a,0x0f,0x17,0x1f,0x2c,0x36,0x42,0x4c,0x4c,0x53,0x5c,0x61,0x68,0x73,0x7b,0x8b,0x93,0x9d,0xa6,0xb6,0xbf,0xc4,0xcb,0xcf };
uchar *p=tune_tab;

///////////////////////M8初始化
void m8init(void)
{
        PORTD=0;           ////PD接LED
        DDRD=0xff;
        DDRC=0XF0;
        PORTC=0X0F;        /////PC接按键,TWI
        DDRB=0XF8;
        PORTB=0XFF;
        TCNT0=216;         //40x256us=10.24ms扫键时间间隔
        TIMSK|=0X01;

}

//////////////////////////////////
//////5897初始化,因比较慢,所以加以延时

void rda5807_ini(void)
{
        wri_5807(0x02,0xd280) ; //  0b1101 0011 1000 0000//禁止,非静音,重低音,不搜索
        _delay_ms(10);
        wri_5807(0x03,0x0000);  //0x00                   //频率87.0-108.0MHZ,0频道(87)
        _delay_ms(10);
        wri_5807(0x04,0x0040);  //0b0000 0000 0100 0000  //75us去加重,使能I2C
        _delay_ms(10);
        wri_5807(0x05,0xbca8);  //0b1000 1110 1010 1000  //搜台门限,天线电流,电子音量
        _delay_ms(10);

}
//////////////////////////////////
////////////////////////调到指定频率,参数是频道号

void tune(uchar chanl)
{
       
        uint tmp;
               
        uint ctr_word=0x0000; //////////频道号占03寄存器的6位到15位,先把6位加以处理
        ctr_word+=chanl;
        ctr_word<<=6;
        ctr_word+=0x0010;
        wri_5807(0x03,ctr_word);
        _delay_ms(10);
        wri_5807(0x02,0xd281);  ////////现在使能芯片,立即针对频道调谐收音
        _delay_ms(35);          ////////要延时这么长,调好了
                       
        tmp=read_5807(0x0a);    /////////读寄存器0X0A其低10位是调谐的频道号
        dispdata=tmp;            ////////用最容易的办法LED二进制显示频道号

}
/////////////////////////////////////////////
///////////////////////定时器溢出中断用于查键
ISR(TIMER0_OVF_vect)
{
        TCNT0=216;
        keyscan_t=1;//for keycheck
        PORTD=dispdata;
       
}

////////////////////////////////////
///////////////////读取键码:状态机法
////////////////////////////////////
uchar readkey(void)
{
uchar keyval=0;
uchar newkey;
static uchar keystate=0;
uchar keyOK;
static uchar lastkey;
        newkey=PINC&0X0F;
        switch(keystate)
        {
                case 0:
                if(newkey!=0x0f)
                {
                keystate=1;
                lastkey=newkey;
                }
                break;
                case 1:
                if(newkey==lastkey)
                {
                keyOK=1;
                keyval=newkey;
                keystate=2;
                }
                else
                keystate=0;
                break;
                case 2:
                if(newkey==0x0f)
                keystate=0;
                break;
        }
        return keyval;
           
}
////////////////////////////////

///////////////////////////////按键处理

void key_act(void)
{
               
        static uchar i=0,ns=0,n=0;
        static uchar vol=8;
        uchar x05,j,k;
       
                switch(keyno)
                {
                        case 0x0e:
                                if (vol<0xff)        //音量+
                                vol++;
                                x05+=vol;
                                wri_5807(0x05,x05);
                        break;
                               
                        case 0x0d:
                                if (vol>0)          //音量-                                                                                                x05+=vol;
                                wri_5807(0x05,x05);
                               
                        break;

                        case 0x0b:
                                tune(*p);                  //频道往下       
                                if (ns>0)
                                ns--;
                                else
                                ns=25;
                                p+=ns;
                       
                        break;

                        case 0x07:
                       
                                tune(*p);                //频道往上
                                if (ns<26)
                                ns++;
                                else
                                ns=0;
                                p+=ns;
                                                                               
                        break;

                }

}
/////////////////////////////////////////////
////////////////////////////////
void main()
{
        m8init();
        twi_ini();
        TCCR0=0X04;         //
        _delay_ms(20);         //等待5897复位
        rda5807_ini();
        asm("sei");
        while(1)
        {
       
        if(keyscan_t)
                {
                        keyscan_t=0;
                        keyno=readkey();
                        key_act();
                }
               
        }
}


再说一句,频率表里的频道号要根据本地调频台确定,5897寄存器具体位含义参见编程指南,通电复位后按按键就可以收台了。简单吧。编程好了以后可以用3V电池。

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2010-2-12 00:24:14 | 显示全部楼层
没有电感的?

出0入0汤圆

 楼主| 发表于 2010-2-12 00:27:35 | 显示全部楼层
图上画的一个小方框在电容旁边,就一个贴片电感。

出0入0汤圆

 楼主| 发表于 2010-2-12 00:32:52 | 显示全部楼层
实物照:

(原文件名:newer 001MI.JPG)


(原文件名:newer 002MI.JPG)

出0入0汤圆

发表于 2010-2-12 09:34:06 | 显示全部楼层
不错,请问收音模块在哪买的?

出0入0汤圆

 楼主| 发表于 2010-2-12 09:39:09 | 显示全部楼层
淘宝,不过要到春节以后了

出0入0汤圆

发表于 2010-2-12 13:32:29 | 显示全部楼层
收音机模块多少MONEY?

出0入0汤圆

 楼主| 发表于 2010-2-12 21:01:06 | 显示全部楼层
贵倒不贵,快递费却高得多。http://item.taobao.com/auction/item_detail-0db2-448b97ff7b70f037855e1171a914bf1d.jhtml?cm_cat=0

出0入0汤圆

发表于 2010-2-12 21:20:21 | 显示全部楼层
mark~

出0入0汤圆

发表于 2010-2-12 21:27:31 | 显示全部楼层
貌似很好玩,哈哈

出0入0汤圆

发表于 2010-2-17 23:28:49 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-2-18 22:32:44 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-2-19 01:04:01 | 显示全部楼层
jh

出0入0汤圆

发表于 2010-2-19 12:10:36 | 显示全部楼层
没带显示的呀

出0入0汤圆

 楼主| 发表于 2010-2-19 12:49:08 | 显示全部楼层
因为本身就是简易的东西,没有加上频率显示否则要复杂点,用LED数码管耗电较大,用1602体积大,一般3V也不好用,用笔段LCD也比较麻烦,所以就使用最土的办法。这是不足之处。

出0入0汤圆

发表于 2010-2-19 18:47:32 | 显示全部楼层
不着急的话叫卖家用信封给你寄过去!
我就是那样子买了两个模块的!

出0入0汤圆

发表于 2010-2-19 18:59:11 | 显示全部楼层
加入自动搜索保存会比较好点吧?
比如搜索到第一个台时保存时就点亮第一个LED,
第二个对应第二个。。。。。。。。。。
最后搜完就播放第一个台,
还有可以加多一排做十位数指示,
还可以做省电状态模式-只保留基本收听,
选完台后全部灭掉LED

出0入0汤圆

发表于 2010-2-19 19:32:17 | 显示全部楼层
本论坛有卖就好了,还没去淘宝买过不放心。

出0入0汤圆

 楼主| 发表于 2010-2-20 22:13:36 | 显示全部楼层
回复【16楼】bbsniua 鹏
-----------------------------------------------------------------------

很好的建议啊!AVR本身就具有EEPROM,存台也不用外加存储器

出0入0汤圆

发表于 2010-2-20 22:23:24 | 显示全部楼层
记号。

出0入0汤圆

发表于 2010-2-28 20:34:44 | 显示全部楼层
说一下搜索电台的灵敏度如何?

出0入0汤圆

发表于 2010-2-28 23:34:19 | 显示全部楼层
mark

出0入0汤圆

 楼主| 发表于 2010-3-1 09:17:36 | 显示全部楼层
发现程序按键处理的音量调节部分有点毛病作如下更正:
原文:
///////////////////////////////按键处理

void key_act(void)
{

static uchar i=0,ns=0,n=0;
static uchar vol=8;
uchar x05,j,k;

switch(keyno)
{
case 0x0e:
if (vol<0xff) //音量+
vol++;
x05+=vol;
wri_5807(0x05,x05);
break;

case 0x0d:
if (vol>0)          //音量-                                 x05+=vol;
wri_5807(0x05,x05);

break;
。。。。。。。。


修改为:
///////////////////////////////按键处理

void key_act(void)
{

static uchar i=0,ns=0,n=0;
static uchar vol=8;
ucharj,k;
uint x05=0xbca0;======================x05为寄存器05的预置值,音量仅为低4位
switch(keyno)
{
case 0x0e:
if (vol<0x0f) //========================音量+ 16级控制
vol++;
x05+=vol;
wri_5807(0x05,x05);
break;

case 0x0d:
if (vol>0)    //========================音量-
vol--;
x05+=vol;
wri_5807(0x05,x05);

break;

出0入0汤圆

发表于 2010-3-1 10:52:32 | 显示全部楼层
记号!有空玩玩!

出0入0汤圆

发表于 2010-3-2 00:59:53 | 显示全部楼层
楼主,能否上传RDA5807P的官方文档,看看和TEA5767的有哪些差别??

出0入0汤圆

 楼主| 发表于 2010-3-2 09:40:50 | 显示全部楼层
回复【24楼】hamipeter
-----------------------------------------------------------------------
RDA5807有两种方式编程,一中和5767相同,另一种完全不一样,编程指南我也是在本站下载的:http://www.ourdev.cn/bbs/bbs_content_all.jsp?bbs_sn=3553907

出0入0汤圆

发表于 2010-4-9 17:02:02 | 显示全部楼层
严重mark

出0入0汤圆

 楼主| 发表于 2010-4-9 18:27:11 | 显示全部楼层
用2313也可以,不过要软模拟I2C,不如M8方便,另外,模块内已经有了50K上拉,所以外接上拉可以省去

出0入0汤圆

发表于 2010-4-10 15:26:13 | 显示全部楼层
mark 有空做一个

出0入0汤圆

发表于 2010-4-10 22:50:29 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-7-13 20:53:04 | 显示全部楼层
为什么写地址是0x22,读地址是0x23????

以下是编程指南的内容:
当控制接口为I2C时用CHIP ID来区分工作模式:
TEA5767 MODE CHIP ID = 1100000B;
RDA5807P MODE CHIP ID = 0010000B.

R是1,W是0

那么应该分别是0x20和0x21吧!

出0入0汤圆

发表于 2010-7-13 21:04:23 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-8-12 09:26:16 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-10-25 22:32:20 | 显示全部楼层
记号下~

出0入0汤圆

发表于 2012-5-12 16:51:02 | 显示全部楼层
mark...,...

出0入0汤圆

发表于 2012-5-12 16:58:33 | 显示全部楼层
mark...,...

出0入0汤圆

发表于 2012-5-14 16:42:01 | 显示全部楼层
谢谢楼主,有时间也玩一个

出0入0汤圆

发表于 2012-7-24 10:54:12 | 显示全部楼层
学习一下

出0入0汤圆

发表于 2013-3-8 10:41:13 | 显示全部楼层
感谢楼主给我们这些小白分享,不过手头只有51单片机
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 09:29

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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