基于BK1088E的全波段收音机的机密文件与学习笔记

[复制链接]
 楼主| gaoyang9992006 发表于 2023-11-16 17:01 | 显示全部楼层 |阅读模式
本帖最后由 gaoyang9992006 于 2025-2-5 18:03 编辑

本帖仅供自己学习,暂时不公开,因为太机密了。。。网上找不到找不到,重点是我的探索发现。。。该帖分享了两个重要大坑:时钟源问题;调谐问题。研究了半个月彻底搞明白了,可以轻松移植到任意单片机了。只要完成了这两个问题,其他的问题都不是问题。其他可以看手册就行了,这两个问题手册看了也解决不了,另外网上也没多少资料,手册下载都收费的,本帖提供全面的官方资料和例程以及研究分析,避坑,填坑。
[payamount]99.99[/payamount]
[pay]以下是收集到的相关资料
BK108X-1.0.6.zip (4.11 MB, 下载次数: 1)
BK1088E软件.rar (577.69 KB, 下载次数: 3)
BK1088ES数据手册 原理图 程序1.zip (2.11 MB, 下载次数: 3)

在开源的Arduino平台的时序基础进行改写的纯C版本
初始化的寄存器值为
REG.h
  1. uint16_t HW_Reg[]={
  2. 0x9252,//0
  3. 0x1080,
  4. 0x0281,
  5. 0x8000,
  6. 0xa0D4,
  7. 0x37CF,//5
  8. 0x086E,     //共晶体0x006E
  9. 0x0181,
  10. 0xAC90,
  11. 0xF98F,
  12. 0x404C,//10
  13. 0x0009,
  14. 0x0000,
  15. 0x0000,
  16. 0x0000,
  17. 0x0000,//15
  18. 0x7B11,
  19. 0x004D,
  20. 0x4000,
  21. 0x4144,
  22. 0xC29A,//20
  23. 0x79F8,
  24. 0x4012,
  25. 0x0054,
  26. 0x341C,
  27. 0x0000,//25
  28. 0x0000,
  29. 0x4CA2,
  30. 0x8820,    //0x8E20
  31. 0x0200,
  32. 0x0000,//30
  33. 0xA8E4,
  34. 0x3264
  35. };
BK1088_I2C.h
  1. #define BK1088E_PIN_SDIO 8
  2. #define BK1088E_PIN_SCLK 9
  3. #define BK1088E_ADRESS 0x80

  4. typedef union
  5. {
  6.     struct
  7.     {
  8.         uint8_t lowByte;
  9.         uint8_t highByte;
  10.     } refined;
  11.     uint16_t raw;
  12. } word16_to_bytes;

  13. void i2cBeginTransaction()
  14. {
  15.     pinMode(BK1088E_PIN_SDIO, OUTPUT);
  16.     pinMode(BK1088E_PIN_SCLK, OUTPUT);
  17.     digitalWrite(BK1088E_PIN_SDIO, HIGH);
  18.     digitalWrite(BK1088E_PIN_SCLK, HIGH);
  19.     delayMicroseconds(1);

  20.     digitalWrite(BK1088E_PIN_SDIO, LOW);
  21.     delayMicroseconds(1);
  22.     digitalWrite(BK1088E_PIN_SCLK, LOW);
  23.     delayMicroseconds(1);
  24.     digitalWrite(BK1088E_PIN_SDIO, HIGH);
  25. }

  26. void i2cEndTransaction()
  27. {
  28.     pinMode(BK1088E_PIN_SDIO, OUTPUT);
  29.     digitalWrite(BK1088E_PIN_SDIO, LOW);
  30.     delayMicroseconds(1);

  31.     digitalWrite(BK1088E_PIN_SCLK, HIGH);
  32.     delayMicroseconds(1);

  33.     digitalWrite(BK1088E_PIN_SDIO, HIGH);
  34.     delayMicroseconds(1);
  35. }

  36. void i2cAck()
  37. {
  38.     pinMode(BK1088E_PIN_SDIO, OUTPUT);
  39.     digitalWrite(BK1088E_PIN_SCLK, LOW);
  40.     digitalWrite(BK1088E_PIN_SDIO, LOW);
  41.     delayMicroseconds(1);
  42.     digitalWrite(BK1088E_PIN_SCLK, HIGH);
  43.     delayMicroseconds(1);
  44.     digitalWrite(BK1088E_PIN_SCLK, LOW);
  45. }

  46. void i2cNack()
  47. {
  48.     pinMode(BK1088E_PIN_SDIO, OUTPUT);

  49.     digitalWrite(BK1088E_PIN_SCLK, LOW);
  50.     digitalWrite(BK1088E_PIN_SDIO, HIGH);
  51.     delayMicroseconds(1);
  52.     digitalWrite(BK1088E_PIN_SCLK, HIGH);
  53.     delayMicroseconds(1);
  54.     digitalWrite(BK1088E_PIN_SCLK, LOW);
  55. }

  56. uint8_t i2cReceiveAck()
  57. {
  58.     uint8_t ack;
  59.     pinMode(BK1088E_PIN_SDIO, INPUT);
  60.     delayMicroseconds(1);

  61.     digitalWrite(BK1088E_PIN_SCLK, HIGH);
  62.     delayMicroseconds(1);

  63.     ack = digitalRead(BK1088E_PIN_SDIO);

  64.     digitalWrite(BK1088E_PIN_SCLK, LOW);
  65.     delayMicroseconds(1);

  66.     return ack;
  67. }

  68. void i2cWriteByte(uint8_t data)
  69. {
  70.     pinMode(BK1088E_PIN_SDIO, OUTPUT);
  71.     delayMicroseconds(1);

  72.     for (int i = 0; i < 8; i++)
  73.     {

  74.         digitalWrite(BK1088E_PIN_SDIO, (bool)(data & BK1088E_ADRESS));

  75.         delayMicroseconds(1);
  76.         digitalWrite(BK1088E_PIN_SCLK, HIGH);
  77.         delayMicroseconds(1);
  78.         digitalWrite(BK1088E_PIN_SCLK, LOW);
  79.         data = data << 1;
  80.     }
  81. }

  82. uint8_t i2cReadByte()
  83. {
  84.     uint8_t value = 0;

  85.     pinMode(BK1088E_PIN_SDIO, INPUT);
  86.     delayMicroseconds(1);

  87.     for (int i = 0; i < 8; i++)
  88.     {
  89.         digitalWrite(BK1088E_PIN_SCLK, HIGH);
  90.         value = value << 1;
  91.         delayMicroseconds(1);
  92.         if (digitalRead(BK1088E_PIN_SDIO))
  93.             value = value | 1;
  94.         digitalWrite(BK1088E_PIN_SCLK, LOW);
  95.         delayMicroseconds(1);
  96.     }

  97.     return value;
  98. }

  99. void writeRegister(uint8_t reg, uint16_t value)
  100. {

  101.     word16_to_bytes data;
  102.     data.raw = value;

  103.     i2cBeginTransaction();
  104.     i2cWriteByte(BK1088E_ADRESS);
  105.     i2cReceiveAck();

  106.     reg = reg << 1; // Converts address and sets to write operation

  107.     i2cWriteByte(reg);
  108.     i2cReceiveAck();

  109.     i2cWriteByte(data.refined.highByte);
  110.     i2cReceiveAck();
  111.     i2cWriteByte(data.refined.lowByte);
  112.     i2cReceiveAck();

  113.     i2cEndTransaction();
  114. }

  115. uint16_t readRegister(uint8_t reg)
  116. {

  117.     word16_to_bytes data;

  118.     i2cBeginTransaction();
  119.     i2cWriteByte(BK1088E_ADRESS);
  120.     i2cReceiveAck();

  121.     reg = (reg << 1) | 1; // Converts address and sets to read operation

  122.     i2cWriteByte(reg);
  123.     i2cReceiveAck();

  124.     data.refined.highByte = i2cReadByte();
  125.     i2cAck();
  126.     data.refined.lowByte = i2cReadByte();
  127.     i2cNack();

  128.     i2cEndTransaction();

  129.     return data.raw;
  130. }
以上为初始化值,以及IO模拟的基于该芯片的I2C时序,由于该芯片采用的I2C不是标准的I2C读写时序,因此推荐采用该IO模拟的方式,对于其他平台的可以通过宏替换映射到pinMode();digitalWrite();digitalRead();等基础IO操作函数。
重要的几个寄存器:
REG07:BIT13为MODE,当该位为0,进入FM工作模式,当该位为1,进入AM工作模式。
REG05:该寄存器包含了控制频段和频道间隔的位,默认设置为0x37CF时候,对于FM则频段为87~108MHz,SPACE则对应100KHz
REG03:频道设置寄存器,该寄存器的最高位为TUNE,用于调谐,后面15个BIT用于设置频道值
调谐频率F=Band + CHAN * SPACE
特别说明,这里不可同时写入让调谐生效。。。。
这也是我最近研究多天发现的秘密,这就是该帖值钱的地方,手册并未说明。
应先写入CHAN值,然后再重写写入TUNE的置位。

例如在以上的默认配置下,若要选台在101.1Mhz
则对REG03的操作应如下
  1. writeRegister(0x03,(1011-870));
  2.   delay(10);
  3.   writeRegister(0x03,(1011-870)|0x8000);
而直接写  writeRegister(0x03,(1011-870)|0x8000);
将无法实现定位到该频道。
另外一个大坑:该芯片直接通过32768Hz无源晶振将无法正常起振,可使用外置的有源晶振或时钟源。推荐使用高精度32768时钟源芯片RX-8025T,还可以提供基于I2C的万年历功能,如果没有外置时钟源,可以使用单片机的IO时钟定时器或者PWM生成一路32768的时钟信号。
对于ESP32在Arduino下可以使用以下函数
  1. #define clockPin 10

  2. void outCLK()
  3. {
  4.   pinMode(clockPin,OUTPUT);
  5.   ledcSetup(1,32768,8);
  6.   ledcAttachPin(clockPin,1);
  7.   ledcWrite(1,127);
  8. }
该函数可以在指定的引脚输出一路非常接近32768Hz的时钟信号,用于驱动BK1088E。
最后给出一个完整的演示
  1. #include"BK1088_I2C.h"
  2. #include "reg.h"

  3. #define clockPin 10

  4. void outCLK()
  5. {
  6.   pinMode(clockPin,OUTPUT);
  7.   ledcSetup(1,32768,8);
  8.   ledcAttachPin(clockPin,1);
  9.   ledcWrite(1,127);
  10. }

  11. void setup()
  12. {
  13.   outCLK();

  14.   Serial.begin(9600);
  15.   while (!Serial);
  16.   Serial.println("\n********Begin!");
  17.   delay(1000);
  18.   //初始化寄存器
  19.   for (int i=0; i<33; i++)
  20.   {
  21.    writeRegister(i,HW_Reg[i]);
  22.   }
  23. //  调谐到101.1MHz
  24.   writeRegister(0x03,(1011-870));
  25.   delay(10);
  26.   writeRegister(0x03,(1011-870)|0x8000);
  27. }

  28. void loop()
  29. {

  30. }
补充,经过实验,使用无源晶振的话,需要给晶振并联一个1.8pF~6pF电容,即可正常起振,其他容量的电容无法提供准确的频率 000.png
[/pay]

最后在不使用库的情况下,短短3几行代码操作一个寄存器即完成了调谐收台的工作。





个人签名:如果你觉得我的分享或者答复还可以,请给我点赞,谢谢。

2045

主题

16350

帖子

222

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