[应用方案] 自制FM收音机

[复制链接]
1337|4
 楼主| Bermanrep 发表于 2016-2-25 22:24 | 显示全部楼层 |阅读模式

单片机控制的哦,用到了24c02,可以掉电存台,4位数码管显示,自动搜索,音量调整,rda5807收音模块,2822音频放大,红外遥控的。
下面是今天6月24日搞出来的程序
  1. #include <reg52.h>
  2. #include <intrins.h>
  3. #include "IIC.h"
  4. #include "delay.h"

  5. sbit K1 = P2^3;//
  6. sbit K2 = P2^2;//
  7. sbit K3 = P2^1;//
  8. sbit K4 = P2^0;//


  9. #define uchar unsigned char
  10. #define uint unsigned int

  11. uchar data IRcode[4]; //定义一个4字节的数组用来存储代码
  12. uchar CodeTemp; //编码字节缓存变量
  13. sbit IRsignal=P3^2; //红外接收头OUT端直接连P3.2(INT0)

  14. uchar chanl=0x00;

  15. unsigned long frequency;

  16. // RDA5807 寄存器
  17. unsigned char RDA_reg_data[8] =
  18. {
  19. 0xd0,0x00, // 02H
  20. 0x00,0x00, // 03H
  21. 0x00,0x40, // 04H
  22. 0x90,0x88, // 05H
  23. };

  24. char code reserve[3]_at_ 0x3b; //保留0x3b开始的3个字节



  25. /*
  26. 红外部分
  27. */
  28. /************************中断0解码服务子程序**********************/
  29. void int0(void) interrupt 0 using 2
  30. {
  31. uchar i,j,k; //循环变量
  32. EA=0;
  33. for(k=0;k<10;k++)
  34. {Delay0_9ms();
  35. if (IRsignal==1) //如果0.9ms后IRsignal=1,说明不是引导码
  36. {k=10;break;}
  37. else if(k==9) //如果持续了10×0.9ms=9ms的低电平,说明是引导码
  38. {while(IRsignal==0);
  39. Delay4_5ms(); //跳过持续4.5ms的高电平
  40. for(i=0;i<4;i++) //分别读取4个字节
  41. {for(j=1;j<=8;j++) //每个字节8个bit的判断
  42. { while(IRsignal==0); //等待上升沿
  43. Delay0_9ms(); //从上升沿那一时刻开始延时0.9ms,再判断IRsignal
  44. if(IRsignal==1) //如果IRsignal是"1",则向右移入一位"1"
  45. {Delay1ms();
  46. CodeTemp=CodeTemp|0x80;
  47. if(j<8) CodeTemp=CodeTemp>>1;
  48. }
  49. else
  50. if(j<8)CodeTemp=CodeTemp>>1;//如果IRsignal是"0",则向右移一位,自动补"0"
  51. }
  52. IRcode[i]=CodeTemp;
  53. CodeTemp=0;
  54. }
  55. for(i=0;i<4;i++) //通过串口将代码发出
  56. {
  57. SBUF=IRcode[i];
  58. while(!TI); //等待一个字节发送完毕
  59. TI=0;
  60. }
  61. Delay();
  62. }
  63. }
  64. EA=1;
  65. }
  66. /***********************串口初始化程序*********************/
  67. void initUart(void)
  68. {
  69. TMOD|=0x20;
  70. SCON=0x50;
  71. PCON|=0x80;
  72. TH1=0xff; //57600bps [url=home.php?mod=space&uid=72445]@[/url] 11.0592MHz
  73. TL1=0xff;
  74. TR1=1;
  75. }


  76. /**********************************************************

  77. 连续写寄存器子函数

  78. **********************************************************/
  79. void RDA5807_write_reg(void)
  80. {
  81. uchar i;

  82. I2C_start();
  83. // 收音模块写入操作
  84. I2C_write_byte(0x20);
  85. // 寄存器连续写操作
  86. for(i=0; i<8; i++)
  87. {
  88. I2C_write_byte(RDA_reg_data[i]);
  89. }
  90. I2C_stop();
  91. }

  92. /**********************************************************

  93. 连续读寄存器子函数

  94. **********************************************************/
  95. void RDA5807_read_reg(uchar *reg_buf)
  96. {
  97. I2C_start();

  98. // 收音模块读取操作
  99. I2C_write_byte(0x21);

  100. // 寄存器连续读操作
  101. reg_buf[0] = I2C_read_byte(I2C_ACK);
  102. reg_buf[1] = I2C_read_byte(I2C_ACK);
  103. reg_buf[2] = I2C_read_byte(I2C_ACK);
  104. reg_buf[3] = I2C_read_byte(I2C_NACK);

  105. I2C_stop();
  106. }

  107. /**********************************************************

  108. 写24c02子函数

  109. **********************************************************/
  110. void a24c02_write(void)
  111. {
  112. I2C_start();//启动总线
  113. I2C_write_byte(0xa0);//发送器件地址
  114. I2C_write_byte(0x00);////发送器件子地址
  115. I2C_write_byte(RDA_reg_data[2]);
  116. I2C_write_byte(RDA_reg_data[3]);
  117. I2C_stop();
  118. }


 楼主| Bermanrep 发表于 2016-2-25 22:25 | 显示全部楼层
  1. /**********************************************************

  2. 读24c02子函数

  3. **********************************************************/
  4. void a24c02_read(void)
  5. {
  6. I2C_start();//启动总线
  7. I2C_write_byte(0xa0);//发送器件地址
  8. I2C_write_byte(0x00);////发送器件子地址
  9. I2C_start();//启动总线
  10. I2C_write_byte(0xa1);//发送器件读地址
  11. RDA_reg_data[2] = I2C_read_byte(I2C_ACK);
  12. RDA_reg_data[3] = I2C_read_byte(I2C_NACK);
  13. I2C_stop();
  14. }
  15. /**********************************************************

  16. 模块上电初始化子函数

  17. **********************************************************/
  18. void RDA5807_power(void)
  19. {
  20. delayms(50);

  21. // 发送软件复位指令
  22. RDA_reg_data[0] = 0x00;
  23. RDA_reg_data[1] = 0x02;
  24. RDA5807_write_reg();

  25. delayms(10);

  26. // 收音模块默认参数
  27. RDA_reg_data[0] = 0xd0;
  28. RDA_reg_data[1] = 0x01;
  29. a24c02_read();//读取保存的频率
  30. RDA_reg_data[3] += 0x10; //调谐启用
  31. RDA5807_write_reg();
  32. }

  33. /**********************************************************

  34. 频率计算子函数

  35. **********************************************************/
  36. void show_frequency(void)
  37. {
  38. unsigned int temp;
  39. temp = (RDA_reg_data[2]*256)+(RDA_reg_data[3]&0xc0); //计算
  40. temp = temp>>6;
  41. frequency = (unsigned long)(100*temp+87000)/100;
  42. }


  43. /**********************************************************

  44. 功能描述:收音模块自动寻台模式

  45. **********************************************************/
  46. void RDA5807_FM_seek(void)
  47. {
  48. uint chan;
  49. uchar reg_data[4] = {0x00, 0x00, 0x00, 0x00};

  50. RDA_reg_data[3] &= ~(1 << 4); //调谐禁用

  51. // 内部自动寻台使能
  52. RDA_reg_data[0] |= (1 << 0); //搜索位置1
  53. RDA5807_write_reg();

  54. // 等待STC 标志置位
  55. while(0 == (reg_data[0] & 0x40))
  56. {
  57. delayms(10);
  58. // 读取内部状态
  59. RDA5807_read_reg(reg_data);
  60. }
  61. // 获取当前工作频点
  62. chan = reg_data[0] & 0x03;
  63. chan = reg_data[1] | (chan << 8);
  64. chan = chan << 6;

  65. // 保存当前工作频点
  66. RDA_reg_data[2] = (chan >> 8) & 0xff;
  67. RDA_reg_data[3] = (chan & 0xff);
  68. a24c02_write();//保存当前频率
  69. }

  70. /************************************************************************
  71. led显示
  72. ************************************************************************/
  73. sbit ge=P2^4;
  74. sbit shi=P2^5;
  75. sbit bai=P2^6;
  76. sbit qan=P2^7;
  77. #define LED P0
  78. //unsigned char tab[]={ 0x3f,0x30,0x6d,0x79,0x72,0x5b,0x5f,0x31,0x7f,0x7b,0x40};//共阴
  79. //0, 1, 2 3 4 5 6 7 8 9
  80. unsigned char tab[]={ 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//共阳
  81. //0, 1, 2 3 4 5 6 7 8 9
 楼主| Bermanrep 发表于 2016-2-25 22:25 | 显示全部楼层
  1. /************************************************************************/
  2. void Led_Display(unsigned long i) //显示函数
  3. {
  4. LED = tab[i/1000];
  5. qan = 1;
  6. if((i/1000)>0)
  7. {qan = 0;}
  8. bai = 1;shi = 1;ge = 1;
  9. delayms(1);

  10. LED = tab[(i%1000)/100];
  11. qan = 1;bai = 0;shi = 1;ge = 1;
  12. delayms(1);

  13. LED = 0x7f&tab[((i%1000)%100)/10];//加个小数点
  14. qan = 1;bai = 1;shi = 0;ge = 1;
  15. delayms(1);

  16. LED = tab[(((i%1000)%100)%10)/1];
  17. qan = 1; bai = 1;shi = 1;ge = 0;
  18. delayms(1);
  19. }




  20. /**********************************************************

  21. 音量显示子函数

  22. **********************************************************/
  23. void show_volume(void)
  24. {
  25. uchar i,vol;
  26. vol=RDA_reg_data[7] & 0x0f; //取音量值
  27. i=90;
  28. while(i--)
  29. {Led_Display(vol*10);}
  30. }

  31. /**********************************************************

  32. 主函数

  33. **********************************************************/
  34. void main(void)
  35. {
  36. initUart();
  37. IT0=1; //INT0为负边沿触发, (1:负边沿触发,0:低电平触发)
  38. EX0=1; //外部中断INT0开, (1:开, 0:关 )
  39. EA=1; //开所有中断
  40. CodeTemp=0; //初始化红外编码字节缓存变量
  41. Delay();



  42. RDA5807_power();

  43. show_frequency();
  44. while(1)
  45. {
  46. //红外遥控检测
  47. if(IRcode[0]==0x00)
  48. {
  49. IRcode[0]=0x1a;
  50. if(IRcode[2]==0x1e)
  51. {
  52. RDA_reg_data[0] &= ~(1 << 1); //向下搜索
  53. RDA5807_FM_seek();
  54. show_frequency();//更新频率
  55. }
  56. if(IRcode[2]==0x0e)
  57. {
  58. RDA_reg_data[0] |= (1 << 1); //向上搜索
  59. RDA5807_FM_seek();
  60. show_frequency();//更新频率
  61. }
  62. if(IRcode[2]==0x4d)
  63. {
  64. if((RDA_reg_data[7] & 0x0f) < 0x0f)
  65. {
  66. RDA_reg_data[0] = 0xd0;
  67. RDA_reg_data[1] = 0x01;
  68. RDA_reg_data[3] &= ~(1 << 4);

  69. RDA_reg_data[7]++; // 音量递增
  70. RDA5807_write_reg();
  71. }
  72. show_volume(); //显示音量
  73. }
  74. if(IRcode[2]==0x1a)
  75. {
  76. if((RDA_reg_data[7] & 0x0f) > 0x00)
  77. {
  78. RDA_reg_data[0] = 0xd0;
  79. RDA_reg_data[1] = 0x01;
  80. RDA_reg_data[3] &= ~(1 << 4);

  81. RDA_reg_data[7]--; // 音量递减
  82. RDA5807_write_reg();
  83. }
  84. show_volume(); //显示音量
  85. }
  86. }
  87. // 红外,,

  88. if(K1 == 0)
  89. {
  90. delayms(20);
  91. if(K1 == 0)
  92. {
  93. while(K1 == 0);
  94. RDA_reg_data[0] |= (1 << 1); //向上搜索
  95. RDA5807_FM_seek();
  96. show_frequency();//更新频率
  97. }
  98. }

  99. if(K2 == 0)
  100. {
  101. delayms(20);
  102. if(K2 == 0)
  103. {
  104. while(K2 == 0);
  105. RDA_reg_data[0] &= ~(1 << 1); //向下搜索
  106. RDA5807_FM_seek();
  107. show_frequency();//更新频率
  108. }
  109. }

  110. if(K3 == 0)
  111. {
  112. delayms(20);
  113. if(K3 == 0)
  114. {
  115. while(K3 == 0);
  116. if((RDA_reg_data[7] & 0x0f) < 0x0f)
  117. {
  118. RDA_reg_data[0] = 0xd0;
  119. RDA_reg_data[1] = 0x01;
  120. RDA_reg_data[3] &= ~(1 << 4);

  121. RDA_reg_data[7]++; // 音量递增
  122. RDA5807_write_reg();
  123. }
  124. show_volume(); //显示音量
  125. }
  126. }

  127. if(K4 == 0)
  128. {
  129. delayms(20);
  130. if(K4 == 0)
  131. {
  132. while(K4 == 0);
  133. if((RDA_reg_data[7] & 0x0f) > 0x00)
  134. {
  135. RDA_reg_data[0] = 0xd0;
  136. RDA_reg_data[1] = 0x01;
  137. RDA_reg_data[3] &= ~(1 << 4);

  138. RDA_reg_data[7]--; // 音量递减
  139. RDA5807_write_reg();
  140. }
  141. show_volume(); //显示音量
  142. }
  143. }
  144. Led_Display(frequency);//显示频率
  145. }
  146. }
deviceplugs 发表于 2016-2-26 21:54 | 显示全部楼层
有LCD显示吗,能收多少个台?
500days 发表于 2016-2-27 20:39 | 显示全部楼层
调台的话是用什么方式,按键吗
您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

132

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部