- uint16_t HW_Reg[]={
- 0x9252,//0
- 0x1080,
- 0x0281,
- 0x8000,
- 0xa0D4,
- 0x37CF,//5
- 0x086E, //共晶体0x006E
- 0x0181,
- 0xAC90,
- 0xF98F,
- 0x404C,//10
- 0x0009,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,//15
- 0x7B11,
- 0x004D,
- 0x4000,
- 0x4144,
- 0xC29A,//20
- 0x79F8,
- 0x4012,
- 0x0054,
- 0x341C,
- 0x0000,//25
- 0x0000,
- 0x4CA2,
- 0x8820, //0x8E20
- 0x0200,
- 0x0000,//30
- 0xA8E4,
- 0x3264
- };
BK1088_I2C.h
- #define BK1088E_PIN_SDIO 8
- #define BK1088E_PIN_SCLK 9
- #define BK1088E_ADRESS 0x80
- typedef union
- {
- struct
- {
- uint8_t lowByte;
- uint8_t highByte;
- } refined;
- uint16_t raw;
- } word16_to_bytes;
- void i2cBeginTransaction()
- {
- pinMode(BK1088E_PIN_SDIO, OUTPUT);
- pinMode(BK1088E_PIN_SCLK, OUTPUT);
- digitalWrite(BK1088E_PIN_SDIO, HIGH);
- digitalWrite(BK1088E_PIN_SCLK, HIGH);
- delayMicroseconds(1);
- digitalWrite(BK1088E_PIN_SDIO, LOW);
- delayMicroseconds(1);
- digitalWrite(BK1088E_PIN_SCLK, LOW);
- delayMicroseconds(1);
- digitalWrite(BK1088E_PIN_SDIO, HIGH);
- }
- void i2cEndTransaction()
- {
- pinMode(BK1088E_PIN_SDIO, OUTPUT);
- digitalWrite(BK1088E_PIN_SDIO, LOW);
- delayMicroseconds(1);
- digitalWrite(BK1088E_PIN_SCLK, HIGH);
- delayMicroseconds(1);
- digitalWrite(BK1088E_PIN_SDIO, HIGH);
- delayMicroseconds(1);
- }
- void i2cAck()
- {
- pinMode(BK1088E_PIN_SDIO, OUTPUT);
- digitalWrite(BK1088E_PIN_SCLK, LOW);
- digitalWrite(BK1088E_PIN_SDIO, LOW);
- delayMicroseconds(1);
- digitalWrite(BK1088E_PIN_SCLK, HIGH);
- delayMicroseconds(1);
- digitalWrite(BK1088E_PIN_SCLK, LOW);
- }
- void i2cNack()
- {
- pinMode(BK1088E_PIN_SDIO, OUTPUT);
- digitalWrite(BK1088E_PIN_SCLK, LOW);
- digitalWrite(BK1088E_PIN_SDIO, HIGH);
- delayMicroseconds(1);
- digitalWrite(BK1088E_PIN_SCLK, HIGH);
- delayMicroseconds(1);
- digitalWrite(BK1088E_PIN_SCLK, LOW);
- }
- uint8_t i2cReceiveAck()
- {
- uint8_t ack;
- pinMode(BK1088E_PIN_SDIO, INPUT);
- delayMicroseconds(1);
- digitalWrite(BK1088E_PIN_SCLK, HIGH);
- delayMicroseconds(1);
- ack = digitalRead(BK1088E_PIN_SDIO);
- digitalWrite(BK1088E_PIN_SCLK, LOW);
- delayMicroseconds(1);
- return ack;
- }
- void i2cWriteByte(uint8_t data)
- {
- pinMode(BK1088E_PIN_SDIO, OUTPUT);
- delayMicroseconds(1);
- for (int i = 0; i < 8; i++)
- {
- digitalWrite(BK1088E_PIN_SDIO, (bool)(data & BK1088E_ADRESS));
- delayMicroseconds(1);
- digitalWrite(BK1088E_PIN_SCLK, HIGH);
- delayMicroseconds(1);
- digitalWrite(BK1088E_PIN_SCLK, LOW);
- data = data << 1;
- }
- }
- uint8_t i2cReadByte()
- {
- uint8_t value = 0;
- pinMode(BK1088E_PIN_SDIO, INPUT);
- delayMicroseconds(1);
- for (int i = 0; i < 8; i++)
- {
- digitalWrite(BK1088E_PIN_SCLK, HIGH);
- value = value << 1;
- delayMicroseconds(1);
- if (digitalRead(BK1088E_PIN_SDIO))
- value = value | 1;
- digitalWrite(BK1088E_PIN_SCLK, LOW);
- delayMicroseconds(1);
- }
- return value;
- }
- void writeRegister(uint8_t reg, uint16_t value)
- {
- word16_to_bytes data;
- data.raw = value;
- i2cBeginTransaction();
- i2cWriteByte(BK1088E_ADRESS);
- i2cReceiveAck();
- reg = reg << 1; // Converts address and sets to write operation
- i2cWriteByte(reg);
- i2cReceiveAck();
- i2cWriteByte(data.refined.highByte);
- i2cReceiveAck();
- i2cWriteByte(data.refined.lowByte);
- i2cReceiveAck();
- i2cEndTransaction();
- }
- uint16_t readRegister(uint8_t reg)
- {
- word16_to_bytes data;
- i2cBeginTransaction();
- i2cWriteByte(BK1088E_ADRESS);
- i2cReceiveAck();
- reg = (reg << 1) | 1; // Converts address and sets to read operation
- i2cWriteByte(reg);
- i2cReceiveAck();
- data.refined.highByte = i2cReadByte();
- i2cAck();
- data.refined.lowByte = i2cReadByte();
- i2cNack();
- i2cEndTransaction();
- return data.raw;
- }
以上为初始化值,以及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的操作应如下
- writeRegister(0x03,(1011-870));
- delay(10);
- writeRegister(0x03,(1011-870)|0x8000);
而直接写 writeRegister(0x03,(1011-870)|0x8000);
将无法实现定位到该频道。
另外一个大坑:该芯片直接通过32768Hz无源晶振将无法正常起振,可使用外置的有源晶振或时钟源。推荐使用高精度32768时钟源芯片RX-8025T,还可以提供基于I2C的万年历功能,如果没有外置时钟源,可以使用单片机的IO时钟定时器或者PWM生成一路32768的时钟信号。
对于ESP32在Arduino下可以使用以下函数
- #define clockPin 10
- void outCLK()
- {
- pinMode(clockPin,OUTPUT);
- ledcSetup(1,32768,8);
- ledcAttachPin(clockPin,1);
- ledcWrite(1,127);
- }
该函数可以在指定的引脚输出一路非常接近32768Hz的时钟信号,用于驱动BK1088E。
最后给出一个完整的演示
- #include"BK1088_I2C.h"
- #include "reg.h"
- #define clockPin 10
- void outCLK()
- {
- pinMode(clockPin,OUTPUT);
- ledcSetup(1,32768,8);
- ledcAttachPin(clockPin,1);
- ledcWrite(1,127);
- }
- void setup()
- {
- outCLK();
- Serial.begin(9600);
- while (!Serial);
- Serial.println("\n********Begin!");
- delay(1000);
- //初始化寄存器
- for (int i=0; i<33; i++)
- {
- writeRegister(i,HW_Reg[i]);
- }
- // 调谐到101.1MHz
- writeRegister(0x03,(1011-870));
- delay(10);
- writeRegister(0x03,(1011-870)|0x8000);
- }
- void loop()
- {
- }
补充,经过实验,使用无源晶振的话,需要给晶振并联一个1.8pF~6pF电容,即可正常起振,其他容量的电容无法提供准确的频率
[/pay]
最后在不使用库的情况下,短短3几行代码操作一个寄存器即完成了调谐收台的工作。