📄 si4700.c
字号:
#include <avr/io.h>
#include <util/twi.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#define F_CPU 1000000 /* 8MHz processor */
/* 设置 TWPS=0 即与分频系数为1 */
#define F_TWI 100000 /* 100KHz */
#define TWBR_SELECT (((F_CPU/F_TWI)-16)/2)
#define UINT8 uint8_t
#define UINT16 uint16_t
#define UINT32 uint32_t
#define BIT_SET(a,b) a|=(1<<b)
#define BIT_CLR(a,b) a&=(~(1<<b))
#define BIT_INV(a,b) a^=(1<<b)
#define BIT_STATUS(a,b) ((a&(1<<b))>>b)
#define DURATION_INIT_1 600ns mininum
#define DURATION_INIT_2 600ns minimum
#define DURATION_INIT_3 600ns minimum
#define DURATION_START_1 600ns minimum
#define DURATION_START_2 600ns minimum
#define DURATION_START_3 800ns minimum
#define DURATION_STOP_1 800ns minimum
#define DURATION_STOP_2 600ns minimum
#define DURATION_STOP_3 1300ns minimum
#define DURATION_HIGH 900ns minimum
#define DURATION_LOW 1600ns minimum
#define POWER_SETTLING 50~100ms
//#define DELAY(DURATION) {unsigned short i; for(i = 1; i <= DURATION; i++){}}
#define scl(i) {if(i) BIT_SET(PORTC,5);else BIT_CLR(PORTC,5);}
#define sda(i) {if(i) BIT_SET(PORTC,4);else BIT_CLR(PORTC,4);}
#define rst(i) {if(i) BIT_SET(PORTC,1);else BIT_CLR(PORTC,1);}
#define sda_pin (BIT_STATUS(PINC,4))
#define READ 0x21
#define WRITE 0x20
UINT8 com_buf;
void ResetSi4700_2w(void)
{
PORTC=0xff;
DDRC=0xff;
sda(0);
rst(0);
scl(1);
//_delay_ms(1);
rst(1);
sda(1);
//_delay_ms(1);
}
unsigned char OperationSi4700_2w(unsigned char operation, unsigned char *data, unsigned char numBytes)
{
unsigned char controlWord, j, error = 0;
int i;
/***************************************************
START: make sure here SDIO_DIR =OUT, SCLK = 1, SDIO = 1
****************************************************/
scl(1);
sda(1);
sda(0);
scl(0);
/***************************************************
WRITE CONTROL DATA: make sure here: SLCK = 0; SDIO = 0
****************************************************/
if(operation == READ)
controlWord = 0x21;
else
controlWord = 0x20;
for(i = 7; i>=0; i--)
{
sda( (controlWord >> i) & 0x01);
//_delay_us(2);
scl(1);
scl(0);
//_delay_us(2);
}
/***************************
CHECK ACK for control word
***************************/
BIT_CLR(DDRC,4);
//_delay_us(2);
scl(1);
if(sda_pin != 0)
{
error = 1;
goto STOP;
}
scl(0);
//_delay_us(2);
/***************************************
WRITE or READ data
****************************************/
for(j = 0; j < numBytes; j++, data++)
{
if(operation == WRITE)
BIT_SET(DDRC,4);
else
BIT_CLR(DDRC,4);
for(i = 7; i>=0; i--)
{
if(operation == WRITE)
sda( (*data >> i) & 0x01);
//_delay_us(2);
scl(1);
if(operation == READ)
*data = (*data << 1) | sda_pin;
scl(0);
//_delay_us(2);
}
/******************************
CHECK ACK or SEND ACK=0
*******************************/
if(operation == WRITE)
BIT_CLR(DDRC,4);
else
{
BIT_SET(DDRC,4);
if(j == (numBytes -1))
sda(1)
else
sda(0)
}
//_delay_us(2);
scl(1);
if(operation == WRITE)
if(sda_pin != 0)
{
error = 1;
goto STOP;
}
scl(0);
//_delay_us(2);
}
/****************************
STOP: make sure here: SCLK = 0
*****************************/
STOP:
BIT_SET(DDRC,4);
sda(0)
scl(1)
sda(1)
//_delay_us(2);
return(error);
}
UINT32 g_bandl=87500,g_bandh=108000;
UINT8 g_space=100,g_vol_level=0x08;
/**************************************
Si4700_Intialization():
after initialization please make sure(FW/B15):
0x00: 0x1242
0x01: 0x080F/0A0F
0x07: 0x3C04
0x08: 0x0008
0x09: 0x0001
***************************************/
void Si4700_Intialization(void)
{
unsigned char si4700_initialization[] = {0x40,0x01,0x00,0x00,0x90,0x04,0x0c,0x18,0x00,0x20,0x81,0x00};
unsigned char error_ind = 0,reg_data[28]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},i;
g_vol_level=si4700_initialization[7]&0xf;
if(si4700_initialization[7]&0xc0==0x00){
g_bandl=87500;
g_bandh=108000;
}
else if(si4700_initialization[7]&0xc0==0x40){
g_bandl=76000;
g_bandh=108000;
}
else if(si4700_initialization[7]&0xc0==0x80){
g_bandl=76000;
g_bandh=90000;
}
if(si4700_initialization[7]&0x30==0x00){
g_space=200;
}
else if(si4700_initialization[7]&0x30==0x10){
g_space=100;
}
else if(si4700_initialization[7]&0x30==0x20){
g_space=50;
}
_delay_ms(100);
ResetSi4700_2w();
error_ind = OperationSi4700_2w(WRITE, &(si4700_initialization[0]), 12);
if(error_ind)
return;
_delay_ms(100);
/////////////////
error_ind = OperationSi4700_2w(READ, reg_data, 26);
if(error_ind)
return;
for(i=0;i<26;i++){
while(!(UCSRA & (1<<UDRE)));//等待发送缓冲器为空
UDR=reg_data[i];
}
//////////
}
/**************************************
Si4700_Channel_Selection()
***************************************/
void Si4700_Channel_Selection(UINT32 frq)
{
unsigned short loop_counter = 0;
unsigned char si4700_reg_data[4];
unsigned char error_ind = 0;
unsigned char si4700_channel_start_tune[] = {0x40,0x01,0x80,0xCA}; //107.7MHz
unsigned char si4700_channel_stop_tune[] = {0x40,0x01,0x00};
si4700_channel_start_tune[3]=(frq-g_bandl)/g_space;//channel
//set tune bit
error_ind = OperationSi4700_2w(WRITE, &(si4700_channel_start_tune[0]), 4);
if(error_ind)
return;
//wait STC=1
do
{
error_ind = OperationSi4700_2w(READ, &(si4700_reg_data[0]), 1);
if(error_ind)
return;
loop_counter++;
}
while(((si4700_reg_data[0]&0x40) == 0) && (loop_counter < 0xff));
loop_counter = 0;
//clear tune bit
error_ind = OperationSi4700_2w(WRITE, &(si4700_channel_stop_tune[0]), 3);
if(error_ind)
return;
//wait STC=0
do
{
error_ind = OperationSi4700_2w(READ, &(si4700_reg_data[0]), 1);
if(error_ind)
return;
loop_counter++;
}
while(((si4700_reg_data[0]&0x40) != 0) && (loop_counter < 0xff));
loop_counter = 0;
//read REG0A&0B
error_ind = OperationSi4700_2w(READ,&(si4700_reg_data[0]), 4);
if(error_ind)
return;
}
/*****************************************************************************************************
Si4700_Channel_Seek()
return 0: good, current channel is valid
return 1: I2C error
return 2: used in SKMODE0, seek fail, no any valid channel, should end seek
return 2: used in SKMODE1, Band Limit, Stop seeking at the upper or lower band limit, should end seek
return 3: AFC rail, current channel is invalid, should seek next one
******************************************************************************************************/
UINT32 Si4700_Channel_Seek_UP(void)
{
unsigned short loop_counter = 0;
unsigned char si4700_reg_data[32];
unsigned char error_ind = 0, seek_error = 0;
unsigned char si4700_channel_seek_start[] = {0x41};
unsigned char si4700_channel_seek_stop[] = {0x40};
UINT32 frq;
//set seek bit
error_ind = OperationSi4700_2w(WRITE,&(si4700_channel_seek_start[0]), 1);
if(error_ind)
return 1;
//wait STC=1
do
{
error_ind = OperationSi4700_2w(READ,&(si4700_reg_data[0]), 1);
if(error_ind)
return 1;
loop_counter++;
_delay_ms(5);
}
while(((si4700_reg_data[0]&0x40) == 0) && (loop_counter < 0xfff)); //for loop_counter, when seek, the loop time must > 2s
loop_counter = 0;
//if you use SKMODE = 0, you can check Seek Fail here
//if you use SKMODE = 1, you can check Band Limit here
if((si4700_reg_data[0]&0x20) != 0)
seek_error = 2;
//you can check AFC Rail here
else if((si4700_reg_data[0]&0x10) != 0)
seek_error = 3;
//clear seek bit
error_ind = OperationSi4700_2w(WRITE,&(si4700_channel_seek_stop[0]), 1);
if(error_ind)
return 1;
//wait STC=0
do
{
error_ind = OperationSi4700_2w(READ,&(si4700_reg_data[0]), 1);
if(error_ind)
return 1;
loop_counter++;
_delay_ms(5);
}
while(((si4700_reg_data[0]&0x40) != 0) && (loop_counter < 0xff));
loop_counter = 0;
//you can read REG0A&0B for channel number or RSSI here
error_ind = OperationSi4700_2w(READ,&(si4700_reg_data[0]), 4);
if(error_ind)
return 1;
frq=(((UINT32)si4700_reg_data[2]<<8)|(UINT32)si4700_reg_data[3])&0x03ff;
return frq*g_space+g_bandl;
//return seek_error;
}
/*****************************************************************************************************
Si4700_Channel_Seek()
return 0: good, current channel is valid
return 1: I2C error
return 2: used in SKMODE0, seek fail, no any valid channel, should end seek
return 2: used in SKMODE1, Band Limit, Stop seeking at the upper or lower band limit, should end seek
return 3: AFC rail, current channel is invalid, should seek next one
******************************************************************************************************/
UINT32 Si4700_Channel_Seek_DOWN(void)
{
unsigned short loop_counter = 0;
unsigned char si4700_reg_data[32];
unsigned char error_ind = 0, seek_error = 0;
unsigned char si4700_channel_seek_start[] = {0x43};
unsigned char si4700_channel_seek_stop[] = {0x40};
UINT32 frq;
//set seek bit
error_ind = OperationSi4700_2w(WRITE,&(si4700_channel_seek_start[0]), 1);
if(error_ind)
return 1;
//wait STC=1
do
{
error_ind = OperationSi4700_2w(READ,&(si4700_reg_data[0]), 1);
if(error_ind)
return 1;
loop_counter++;
_delay_ms(5);
//if(loop_counter==1000)UDR=si4700_reg_data[0];
}
while((si4700_reg_data[0]&0x40) == 0); //for loop_counter, when seek, the loop time must > 2s
//while(((si4700_reg_data[0]&0x40) == 0) && (loop_counter < 0xfff)); //for loop_counter, when seek, the loop time must > 2s
loop_counter = 0;
//if you use SKMODE = 0, you can check Seek Fail here
//if you use SKMODE = 1, you can check Band Limit here
if((si4700_reg_data[0]&0x20) != 0)
seek_error = 2;
//you can check AFC Rail here
else if((si4700_reg_data[0]&0x10) != 0)
seek_error = 3;
//clear seek bit
error_ind = OperationSi4700_2w(WRITE,&(si4700_channel_seek_stop[0]), 1);
if(error_ind)
return 1;
//wait STC=0
do
{
error_ind = OperationSi4700_2w(READ,&(si4700_reg_data[0]), 1);
if(error_ind)
return 1;
loop_counter++;
}
while((si4700_reg_data[0]&0x40) != 0);
//while(((si4700_reg_data[0]&0x40) != 0) && (loop_counter < 0xff));
loop_counter = 0;
//you can read REG0A&0B for channel number or RSSI here
error_ind = OperationSi4700_2w(READ,&(si4700_reg_data[0]), 4);
if(error_ind)
return 1;
frq=(((UINT32)si4700_reg_data[2]<<8)|(UINT32)si4700_reg_data[3])&0x03ff;
return frq*g_space+g_bandl;
//return seek_error;
}
void Si4700_mute_en(void){
unsigned char si4700_mute_data[1]={0x00};
OperationSi4700_2w(WRITE,si4700_mute_data, 1);
}
void Si4700_mute_dis(void){
unsigned char si4700_mute_data[1]={0x40};
OperationSi4700_2w(WRITE,si4700_mute_data, 1);
}
void Si4700_vol_up(void){
unsigned char si4700_vol_data[] = {0x40,0x01,0x00,0x00,0x90,0x04,0x0c,0x1f};
g_vol_level++;
if(g_vol_level<0||g_vol_level>15)
g_vol_level=15;
else{
si4700_vol_data[7]=g_vol_level|0x10;
OperationSi4700_2w(WRITE,si4700_vol_data, 8);
}
}
void Si4700_vol_down(void){
unsigned char si4700_vol_data[] = {0x40,0x01,0x00,0x00,0x90,0x04,0x0c,0x1f};
g_vol_level--;
if(g_vol_level<0||g_vol_level>15)
g_vol_level=0;
else{
si4700_vol_data[7]=g_vol_level|0x10;
OperationSi4700_2w(WRITE,si4700_vol_data, 8);
}
}
void ini_uart(uint16_t m_baud)//m_baud=207时,bode=4800 f=8M //12,9600,1//25,4800,1
{
UBRRH = (uint8_t)(m_baud>>8);
UBRRL = (uint8_t)m_baud;
UCSRA = (1<<U2X);
/* 设置帧格式: 8 个数据位, 1 个停止位*/
UCSRC = (1<<URSEL)|(3<<UCSZ0);
/* 接收器与发送器终端使能,接收器与发送器使能*/
UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);//|(1<<TXCIE);
/*禁用终端
cli();*/
}
SIGNAL(SIG_UART_RECV){
com_buf=UDR;
while(!(UCSRA & (1<<UDRE)));//等待发送缓冲器为空
UDR=com_buf;
}
int main(){
//UINT8 txt[14],i;
UINT32 frq;
UINT8 reg[2];
UINT16 i;
ini_uart(12);//9600/1M
sei();
UDR=0xaa;
//wdt_enable(WDTO_2S);
Si4700_Intialization();
while(1){
//wdt_reset();
switch (com_buf) {
case 1:
com_buf=0;
frq=Si4700_Channel_Seek_DOWN();
frq/=100;
i=((frq/1000)<<12)|(((frq/100)%10)<<8)|(((frq/10)%10)<<4)|((frq/1)%10);
while(!(UCSRA & (1<<UDRE)));UDR=i>>8;
while(!(UCSRA & (1<<UDRE)));UDR=i;
break;
case 2:
com_buf=0;
frq=Si4700_Channel_Seek_UP();
frq/=100;
i=((frq/1000)<<12)|(((frq/100)%10)<<8)|(((frq/10)%10)<<4)|((frq/1)%10);
while(!(UCSRA & (1<<UDRE)));UDR=i>>8;
while(!(UCSRA & (1<<UDRE)));UDR=i;
break;
case 3:
com_buf=0;
Si4700_mute_en();
break;
case 4:
com_buf=0;
Si4700_mute_dis();
break;
case 5:
com_buf=0;
Si4700_vol_up();
break;
case 6:
com_buf=0;
Si4700_vol_down();
break;
case 7:
com_buf=0;
Si4700_Channel_Selection(104000);
break;
case 8:
com_buf=0;
OperationSi4700_2w(READ,reg, 2);
while(!(UCSRA & (1<<UDRE)));UDR=reg[1];
break;
case 9:
com_buf=0;
reg[0]=0x60;
OperationSi4700_2w(WRITE,reg, 1);//mono
break;
case 10:
com_buf=0;
reg[0]=0x40;
OperationSi4700_2w(WRITE,reg, 1);//strero
break;
}}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -