先看效果圖: 顯示 頻道CH , 頻率 100.0Mhz
歡迎信息,1602 內置日文平假名, 正好用來顯示博主名稱。
焊接前,已經萬能面包板上試驗成功。
焊接完成以后,1602 的D0 - D7 接到了 P1 上面,為了布線簡單,這里是接反的 P1.0 => D7 .. 實際寫入 讀取數據時,還需要轉換高低位。
背面走線圖
元件清單:stc89c52, lcd1602, tea5767完整版 , at24c04 , DS18B20 (未實現功能,打算后期在加一個 RTC 芯片,和 GPS 做 精准的電子鍾)
下面是一些元件介紹:
紅外一體化接收頭,常見有2種。
lcd1602 顯示日文假名字符對應表
高位 + 低位,組成一個 unsigned char 放入就能顯示出來了。
下面講源程序:
main.c 主程序中 初始化了 LCD1602 , TEA5767 , 初始化紅外線中斷 , 對按鍵進行掃描。 1 #include <reg52.h>
2 #include "tea5767.h" 3 #include "delay.h" 4 #include "lcd1602.h" 5 #include "IR.h" 6 //K1:上一台 K2:下一台 K3:從低向高搜索台 9 sbit K1 = P2 ^ 1; 10 sbit K2 = P2 ^ 4; 11 sbit K3 = P2 ^ 7; 12 13 //當前頻道號 從 0 開始 14 unsigned char ch = 0; 15 16 void main() 17 { 18 19 //初始化 1602lcd 20 lcd1602_init(); 21 22 //初始化 串口 23 init_uart(); 24 25 //初始化紅外遙控接口 26 init_IR(); 27 28 //主函數中掃描按鍵 29 while(1) 30 { 31 //上一台 32 if(0 == K1) 33 { 34 //去抖動 35 delayms(100); 36 if(0 == K1) 37 { 38 set_ch(--ch); 39 } 40 } 41 //下一台 42 if(0 == K2) 43 { 44 //去抖動 45 delayms(100); 46 if(0 == K2) 47 { 48 set_ch(++ch); 49 } 50 } 51 //自動搜索 52 if(0 == K3) 53 { 54 //去抖動 55 delayms(100); 56 if(0 == K3) 57 { 58 tea5767_tiny_auto_search(); 59 } 60 } 61 } 62 } 63 64 void IR_int() interrupt 0 65 { 66 IR_CODE ir_code; 67 EX0 = 0;//處理過程中 關中斷 68 ir_code = IR_recv(); 69 if(ir_code.ir_code) 70 { 73 /** 74 * custom:0xCC1D code:0x05FA 上一台 75 * custom:0xCC1D code:0x06F9 下一台 76 * custom:0xCC1D code:0x01FE 靜音 77 */ 78 //比較機器碼 79 if(ir_code.custom_height == 0xcc && ir_code.custom_lower == 0x1d) 80 { 81 //比較功能碼 82 switch(ir_code.ir_code) 83 { 84 case 0x5: set_ch(++ch); break; 85 case 0x6: set_ch(--ch); break; 86 case 0x1: tea5767_mute(ch); break; 87 } 88 //發送到串口,顯示出編碼,可用於記錄編碼,做學習型遙控器
92 send_code(ir_code); 93 } 94 } 95 EX0 = 1;//處理結束后 開中斷 96 }
lcd1602.h
1 #ifndef __LCD1602__ 2 #define __LCD1602__ 3 #include <reg52.h> 4 #include "delay.h" 9 #define DATA P1 10 sbit RS = P3 ^ 7;//數據 H 命令 L 11 sbit RW = P3 ^ 4;//讀 H 寫 L 12 sbit E = P3 ^ 3;//高電平 H 使能 13 14 /**19 * E = 1 后需要等一小段時間, 在手冊中並沒有說明 - 20 */ 21 void lcd1602_init(); 22 void lcd1602_clear(); 23 char lcd1602_is_busy(); 24 void lcd1602_write_cmd(unsigned char cmd); 25 void lcd1602_write_data(unsigned char dat); 26 void lcd1602_pos(unsigned char pos); 27 unsigned char lcd1602_reverse(unsigned char dat); 28 #endif
lcd1602.c
1 #include "lcd1602.h" 2 3 void lcd1602_init() 4 { 5 //初始化 復位 lcd1602 6 lcd1602_write_cmd(0x38);//設置顯示模式 指令碼 00111000 => 0x38 7 delayms(1); 8 lcd1602_write_cmd(0x0c);//開顯示 不顯示光標 不閃爍 9 delayms(1); 10 lcd1602_write_cmd(0x06);//光標設置 寫字符后指針加一 11 delayms(1); 12 lcd1602_write_cmd(0x01);//光標清0 指針清0 13 delayms(1); 14 //設置初始位置為 0 15 lcd1602_pos(0); 16 //打印歡迎信息 日文假名 17 /** 18 * こんにちわ ねじ 20 * こ 高4位是 b 低4位是 a 合並就是 0xba 21 */ 22 lcd1602_write_data(0xba); 23 lcd1602_write_data(0xdd); 24 lcd1602_write_data(0xc6); 25 lcd1602_write_data(0xc1); 26 lcd1602_write_data(0xca); 27 lcd1602_pos(13); 28 lcd1602_write_data(0xc8); 29 lcd1602_write_data(0xbd); 30 lcd1602_write_data(0xde); 31 32 //第二行顯示 Welcome Radio 33 lcd1602_pos(40); 34 lcd1602_write_data('W'); 35 lcd1602_write_data('e'); 36 lcd1602_write_data('l'); 37 lcd1602_write_data('c'); 38 lcd1602_write_data('o'); 39 lcd1602_write_data('m'); 40 lcd1602_write_data('e'); 41 lcd1602_pos(0x4b); 42 lcd1602_write_data('R'); 43 lcd1602_write_data('a'); 44 lcd1602_write_data('d'); 45 lcd1602_write_data('i'); 46 lcd1602_write_data('o'); 47 } 48 49 50 void lcd1602_clear() 51 { 52 lcd1602_write_cmd(0x01);//光標清0 指針清0 53 } 54 55 void lcd1602_pos(unsigned char pos) 56 { 57 //設置指針位置 0x80 | 位置 58 lcd1602_write_cmd(pos|0x80); 59 } 60 61 void lcd1602_write_data(unsigned char dat) 62 { 63 while(lcd1602_is_busy()); 64 RS = 1; 65 RW = 0; 66 E = 0; 67 DATA = lcd1602_reverse(dat); 68 delayms(1); 69 E = 1;//在E 高向低變化時傳輸 70 E = 0; 71 } 72 73 void lcd1602_write_cmd(unsigned char cmd) 74 { 75 while(lcd1602_is_busy()); 76 RS = 0; 77 RW = 0; 78 E = 0; 79 DATA = lcd1602_reverse(cmd); 80 delayms(1); 81 E = 1; //在E 高向低變化時傳輸 82 E = 0; 83 } 84 85 char lcd1602_is_busy() 86 { 87 char result; 88 RS = 0; //發送的是命令 89 RW = 1; //讀 90 E = 1; //使能 91 delayms(1); 92 result = (1<<7 & lcd1602_reverse(DATA));//7bit 1 忙 0 不忙 93 E = 0; //取消使能 94 return result; 95 } 96 97 98 //字符高低位互換 99 unsigned char lcd1602_reverse(unsigned char dat) 100 { 101 unsigned char chr; 102 chr = (dat>>7 & 1) << 0; 103 chr |= (dat>>6 & 1) << 1; 104 chr |= (dat>>5 & 1) << 2; 105 chr |= (dat>>4 & 1) << 3; 106 chr |= (dat>>3 & 1) << 4; 107 chr |= (dat>>2 & 1) << 5; 108 chr |= (dat>>1 & 1) << 6; 109 chr |= (dat>>0 & 1) << 7; 110 return chr; 111 }
串口 URAT
uart.h
1 #ifndef __UART__ 2 #define __UART__ 3 #include "IR.h" 4 void init_uart(); 5 void send_hex(unsigned char); 6 void send_str(unsigned char *); 7 void send_code(IR_CODE); 8 #endif
uart.c
1 #include <reg52.h> 2 #include "uart.h" 3 void init_uart() 4 { 5 //定時器1 溢出決定波特率 6 EA = 1; //總中斷開 7 TMOD |= 1<<5; //定時器1 自動重裝模式 8 TH1 = 0xfd; //當TL1中溢出時 TH1 的值自動重裝進去 9 TL1 = 0xfd; //省去一個中斷處理函數 10 TR1 = 1; //開始計數 11 SM0 = 0; 12 SM1 = 1; //8bit UART 波特率可變 13 } 14 15 void send_str(unsigned char *str) 16 { 17 while(*str) 18 { 19 SBUF = *str; 20 while(! TI); 21 TI = 0; 22 str++; 23 } 24 } 25 26 void send_hex(unsigned char hex) 27 { 28 SBUF = hex; 29 while(! TI); 30 TI = 0; 31 } 32 33 void send_code(IR_CODE ir_code) 34 { 35 unsigned char c; 36 unsigned char *p; 37 int i,j; 38 p = (unsigned char *)&ir_code; 39 send_str("custom:0x"); 40 for(i=0; i<4; i++) 41 { 42 if(2 == i) 43 { 44 send_str(" code:0x"); 45 } 46 for(j=1; j>=0; j--) 47 { 48 c = (*p>>(4*(j))) & 0xf; 49 if(0<=c && c<=9) 50 { 51 send_hex('0' + c); 52 } 53 else 54 { 55 send_hex('A' + c - 0xa); 56 } 57 } 58 p++; 59 } 60 send_str("\r\n"); 61 }
eeprom.h
1 #include <reg52.h> 2 #ifndef __EEPROM__ 3 #define __EEPROM__ 4 /** 5 * STC90C52 結尾是 90C 6 * EEPROM 5K 7 * SRAM 215字節 8 * 每個扇區512字節 5K / 512 = 10 個扇區 9 * 扇區首地址 2000h 結束地址 33ffh 10 */ 11 12 /* FLASH 首地址 */ 13 #define BASE_ADDR 0x2000 //stc89c52 stc89c52rd 14 //#define BASE_ADDR 0x4000 //stc89c54rd+ 15 16 /* 特殊功能寄存器聲明 */ 17 sfr ISP_DATA = 0xe2; 18 sfr ISP_ADDRH = 0xe3; 19 sfr ISP_ADDRL = 0xe4; 20 sfr ISP_CMD = 0xe5; 21 sfr ISP_TRIG = 0xe6; 22 sfr ISP_CONTR = 0xe7; 23 24 /* 定義命令字節 */ 25 #define CMD_Read 0x01 //字節讀數據命令 26 #define CMD_Prog 0x02 //字節編程數據命令 27 #define CMD_Erase 0x03 //扇區擦除數據命令 28 #define En_Wait_ISP 1<<7 | 1<<1 //設置等待時間 ,並使能ISP/IAP 11.0592 晶振 29 30 void eeprom_lock_ISP(); 31 void eeprom_erase(unsigned int); 32 unsigned char eeprom_read(unsigned int); 33 void eeprom_prog(unsigned int addr, unsigned char dat); 34 35 #endif
延時
delay.h
1 #ifndef __DELAY__ 2 #define __DELAY__ 3 void delayms(int); 4 void delay700us(); 5 #endif
delay.c
1 #include <intrins.h> 2 #include "delay.h" 3 void delayms(int ms) //@11.0592MHz 4 { 5 unsigned char i, j; 6 while(ms--) 7 { 8 _nop_(); 9 i = 2; 10 j = 199; 11 do 12 { 13 while (--j); 14 } 15 while (--i); 16 } 17 } 18 19 void delay700us() //@11.0592MHz 20 { 21 unsigned char i, j; 22 _nop_(); 23 i = 2; 24 j = 61; 25 do 26 { 27 while (--j); 28 } while (--i); 29 }
i2c 通信
i2c.h
1 #ifndef __I2C__ 2 #define __I2C__ 3 4 #include <reg52.h> 5 6 /* 引腳定義 */ 7 sbit I2C_SCL = P3 ^ 5; 8 sbit I2C_SDA = P3 ^ 6; 9 10 void i2c_start(); 11 void i2c_stop(); 12 void i2c_send(unsigned char dat); 13 unsigned char i2c_recv(); 14 char i2c_wait_ack(); 15 void i2c_send_ack(); 16 #endif
i2c.c
1 #include "i2c.h" 2 3 void i2c_start() 4 { 5 /* SCL SDA 為高電平時 SDA 變為低電平 */ 6 I2C_SCL = 1; 7 I2C_SDA = 1; 8 I2C_SDA = 0; 9 I2C_SCL = 0; /* 鉗住I2C總線,准備發送或接收數據 */ 10 } 11 12 void i2c_stop() 13 { 14 /* SCK 高電平期間 SDA 由低變高 */ 15 I2C_SCL = 0; 16 I2C_SDA = 0; 17 I2C_SCL = 1; 18 I2C_SDA = 1; 19 } 20 21 void i2c_send(unsigned char dat) 22 { 23 char i = 8; 24 while(i--) 25 { 26 I2C_SCL = 0; 27 if(dat & 0x80) 28 { 29 I2C_SDA = 1; 30 } 31 else 32 { 33 I2C_SDA = 0; 34 } 35 I2C_SCL = 1; 36 dat = dat<<1; 37 } 38 //等待ACK回復信號 39 i2c_wait_ack(); 40 } 41 42 unsigned char i2c_recv() 43 { 44 unsigned char dat = 0; 45 char i = 8; 46 I2C_SDA = 1; 47 while(i--) 48 { 49 I2C_SCL = 0; 50 dat<<=1; //這里要有一定延時要求是 > 1.3us 51 I2C_SCL = 1; 52 if(I2C_SDA) 53 { 54 //以下3者結果一樣 55 //dat++; 56 //dat += 1; 57 dat |= 1; 58 } 59 //dat |= (unsigned char)I2C_SDA; 60 } 61 i2c_send_ack(); 62 return dat; 63 } 64 65 //無響應返回0 66 char i2c_wait_ack() 67 { 68 unsigned char time_out = 0xff; 69 I2C_SCL = 0; 70 I2C_SDA = 1; 71 I2C_SCL = 1; 72 73 //由 slaver 拉低 SDA 表示回應 74 while(I2C_SDA) 75 { 76 time_out--; 77 if(0 == time_out) 78 { 79 i2c_stop(); 80 return 0; 81 } 82 } 83 return 1; 84 } 85 86 void i2c_send_ack() 87 { 88 //拉低SDA 響應ACK 當SCL 由低電平變高電平時 從機接收 89 I2C_SCL = 0; 90 I2C_SDA = 0; 91 I2C_SCL = 1; 92 I2C_SCL = 0; 93 }
IR 紅外接收
IR.h
1 #ifndef __IR__ 2 #define __IR__ 3 #include <reg52.h> 4 #include "delay.h" 5 #include <string.h> 6 7 //公用 8 typedef struct { 9 unsigned char custom_height; 10 unsigned char custom_lower; 11 unsigned char ir_code; 12 unsigned char re_ir_code; 13 } IR_CODE, *pIR_CODE; 14 15 //接收 16 sbit IR = P3 ^ 2;//紅外線一體接收頭 OUT 17 18 void init_IR(); 19 IR_CODE IR_recv(); 20 #endif
IR.c
1 #include "IR.h" 2 3 void init_IR() 4 { 5 //接收 6 EA = 1; //總中斷開 7 EX0 = 1; //IR 接收頭使用外部中斷0 來處理 8 IT0 = 1; //下降沿觸發 9 } 10 11 //接收 12 IR_CODE IR_recv() 13 { 14 /** 15 * 數據格式: 16 * 9ms低電平 4.5ms高電平 頭部 17 * 定制高位 定制低位 數據碼 數據反碼 18 * 1: 560us低電平 1680us高電平 0.56ms 1.7ms 19 * 0: 560us低電平 560us高電平 0.56ms 0.56ms 20 */ 21 IR_CODE ir_code; 22 unsigned char i,k; 23 unsigned char *ir_char_p; 24 unsigned char ir_char; 25 ir_char_p = (unsigned char *)&ir_code; 26 27 //棧分配 IR_CODE 竟然還要手動清0 28 memset(&ir_code, 0, 4); 29 30 delayms(5); //9ms 內必須是低電平否則就不是頭信息 31 if(0 == IR) 32 { 33 while(! IR);//等待4.5ms的高電平 34 35 //檢測是否是 2.5ms 重碼 36 delayms(3); 37 if(1 == IR) 38 { 39 //k 4位編碼 40 for(k=0; k<4; k++) 41 { 42 ir_char = 0x0; 43 //i 每一個編碼的 8bit 44 for(i=0;i<8;i++) 45 { 46 while(IR); //等待變為低電平時 47 while(! IR); //等待變為高電平后 48 delay700us(); //休眠700us 后讀值 49 ir_char |= (char)IR << i;//先存低位 50 //使用下面指針操作就會失敗出現不穩定 51 //*ir_char_p |= (char)IR << i; 52 } 53 *ir_char_p = ir_char; 54 ir_char_p++; 55 } 56 57 //計算反碼 code碼是否正確 58 if(ir_code.ir_code != ~(ir_code.re_ir_code)) 59 { 60 memset(&ir_code, 0, 4); 61 } 62 } 63 } 64 return ir_code; 65 }
str 處理相關
str.h
1 #ifndef __STR__ 2 #define __STR__ 4 unsigned char num_to_str(unsigned char num); 5 #endif
str.c
1 #include "str.h" 2 3 unsigned char num_to_str(unsigned char num) 4 { 5 unsigned char chr; 6 //asc2 表 0 在前面 7 if(0<= num && 9>= num) 8 { 9 chr = num + '0'; 10 } 11 return chr; 12 }
重點TEA5767 特別說明的是,我先是在TB上找了許多資料,百度上找,但是就發現就是那一種格式的寫法,還是個錯誤的寫法,根本就不對,很多人還轉來轉去。(自動搜台的寫法不對。)
GOOGLE 上搜了下,C51 的不多,其它的有不少。
自動搜台,是利用第6位的 SM ,寫1 表示進入這個模式,同時還需要設置 SSL1 SSL0 ,經過我的測試,發現 HLSI 只能設為1 的時候,才能搜到台。
別人的程序錯誤之處在於, 自動搜索后,從 第3個 讀的數據中找 HLSI 在計算是 + 225 還是 -225 ,這個在讀的時候,就變成IF 了,沒有看datasheet 就寫程序,還說 自動搜索模式有問題,不好用。
經過我的試驗,發現 自動搜台模式,基本能用,但是程序要復雜一些。不像是寫入一個頻率,讀 ADC 比較數值,大於多少就表示有台。 比這種要復雜的多。
以下 2 種算法,都有編寫,並測試成功,但實際試驗效果來看, 第2種,普通的寫法,效果好些。(問題是,自動搜台,檢測到信號停住的地方,可能並不准,有可能是,100.023 這種。如果把 每次步進頻率改為100K 就會錯過很多台,這里是每次進10K)
tea5767.h
1 #ifndef __TEA5767__ 2 #define __TEA5767__ 3 4 #include <string.h> 5 #include "i2c.h" 6 #include "uart.h" 7 #include "str.h" 8 #include "delay.h" 9 #include "lcd1602.h" 10 #include "eeprom.h" 11 12 typedef struct{ 13 unsigned char st1; 14 unsigned char st2; 15 unsigned char st3; 16 unsigned char st4; 17 unsigned char st5; 18 } TEA_DAT, *PTEA_DAT; 19 20 typedef struct { 21 unsigned char high; //表示整數 100 22 unsigned char low; //表示小數 5 23 } TEA_CH, *PTEA_CH; 24 25 /* 地址定義 */ 26 #define TEA5767_ADDR_W 0xc0 //tea5767 寫地址 27 #define TEA5767_ADDR_R 0xc1 //tea5767 讀地址 28 #define TEA5767_CLK 32768 //tea5767 晶振 29 #define TEA5767_MAX_KHZ 108000 //最高頻率 108M 30 #define TEA5767_MIN_KHZ 87500 //最低頻率 87.5M 31 #define TEA5756_HLSI //高混頻器 經過測試,使用SM自動搜索功能時必須設此值 手動搜索 無所謂 32 33 unsigned long tea5767_Khz_to_pll(unsigned long Khz); 34 unsigned long tea5767_pll_to_Khz(TEA_DAT dat); 35 TEA_DAT tea5767_set_receiver(unsigned long Khz); 36 TEA_DAT tea5767_search(unsigned long Khz); 37 void tea5767_auto_search(); 38 void tea5767_tiny_auto_search(); 39 void tea5767_write(TEA_DAT dat); 40 TEA_DAT tea5767_read(); 41 void tea5767_mute(unsigned char ch_num); 42 43 //Lcd顯示 44 void sohw_search(unsigned long Khz, unsigned char channel); 45 //存儲電台 46 void save_eeprom(unsigned long Khz, unsigned char channel); 47 //設定ch 48 unsigned long set_ch(unsigned char ch_num); 49 #endif
tea5767.c
1 #include "tea5767.h" 2 3 unsigned char mute = 1; 4 void tea5767_mute(unsigned char ch_num) 5 { 6 TEA_DAT dat; 7 unsigned long Khz,pll; 8 Khz = set_ch(ch_num); 9 //靜音位寫 1 10 pll = tea5767_Khz_to_pll(Khz); 11 dat.st1 = (mute%2) <<7 | (pll>>8) & 0x3f; 12 dat.st2 = pll; 13 dat.st3 = 1; 14 #ifdef TEA5756_HLSI 15 dat.st3 |= 1<<4; 16 #endif 17 dat.st4 = 0x11; 18 dat.st5 = 0x40; 19 tea5767_write(dat); 20 21 if(mute%2) 22 { 23 lcd1602_pos(40); 24 lcd1602_write_data('M'); 25 lcd1602_write_data('U'); 26 lcd1602_write_data('T'); 27 lcd1602_write_data('E'); 28 } 29 mute++; 30 } 31 32 unsigned long tea5767_Khz_to_pll(unsigned long Khz) 33 { 34 #ifdef TEA5756_HLSI 35 return 4*(Khz*1000+225000)/TEA5767_CLK; 36 #else 37 return 4*(Khz*1000-225000)/TEA5767_CLK; 38 #endif 39 } 40 41 unsigned long tea5767_pll_to_Khz(TEA_DAT dat) 42 { 43 unsigned long Khz,pll; 44 pll = ((dat.st1 & 0x3f)<<8 | dat.st2); 45 #ifdef TEA5756_HLSI 46 Khz = (pll*TEA5767_CLK/4-225*1000)/1000; 47 #else 48 Khz = (pll*TEA5767_CLK/4+225*1000)/1000; 49 #endif 50 51 return Khz; 52 } 53 54 void tea5767_write(TEA_DAT dat) 55 { 56 i2c_start(); 57 i2c_send(TEA5767_ADDR_W); 58 i2c_send(dat.st1); 59 i2c_send(dat.st2); 60 i2c_send(dat.st3); 61 i2c_send(dat.st4); 62 i2c_send(dat.st5); 63 i2c_stop(); 64 } 65 66 TEA_DAT tea5767_read() 67 { 68 TEA_DAT dat; 69 i2c_start(); 70 i2c_send(TEA5767_ADDR_R); 71 dat.st1 = i2c_recv(); 72 dat.st2 = i2c_recv(); 73 dat.st3 = i2c_recv(); 74 dat.st4 = i2c_recv(); 75 dat.st5 = i2c_recv(); 76 i2c_stop(); 77 return dat; 78 } 79 80 TEA_DAT tea5767_set_receiver(unsigned long Khz) 81 { 82 unsigned long pll; 83 TEA_DAT dat; 84 85 pll = tea5767_Khz_to_pll(Khz); 86 87 /* 發送5個控制位 順序是 1 2 3 4 5 字節的高位先發 88 * HLSL = 0 : 4*(102.4*1000000-225*1000)/32768 89 * HLSL = 1 : 4*(102.4*1000000+225*1000)/32768 90 * PLL WORD = 0x30ef 91 */ 92 dat.st1 = (pll>>8) & 0x3f; 93 dat.st2 = pll; 94 dat.st3 = 1; 95 #ifdef TEA5756_HLSI 96 dat.st3 |= 1<<4; 97 #endif 98 dat.st4 = 0x11; 99 dat.st5 = 0x40; 100 101 tea5767_write(dat); 102 delayms(100); 103 dat = tea5767_read(); 104 return dat; 105 } 106 107 //自動搜索 87.5 ~ 108M 由低向高搜索 108 TEA_DAT tea5767_search(unsigned long Khz) 109 { 110 unsigned long pll; 111 TEA_DAT dat; 112 113 pll = tea5767_Khz_to_pll(Khz); 114 dat.st1 = ((pll>>8) & 0x3f) | (1<<6); 115 dat.st2 = pll; 116 //搜索停止 信號強度 01:5 10:7 11:10 117 //dat.st3 = 1 | 1<<7 | 1<<6 |1<<5 ; 118 dat.st3 = 1 | 1<<7 | 1<<6 ; 119 #ifdef TEA5756_HLSI 120 dat.st3 |= 1<<4; 121 #endif 122 123 dat.st4 = 0x11; 124 dat.st5 = 0x40; 125 tea5767_write(dat); 126 delayms(100); 127 dat = tea5767_read(); 128 while(dat.st1 != (dat.st1 | (1<<7))) 129 { 130 dat = tea5767_read(); 131 } 132 return dat; 133 } 134 135 //自動搜台 存台到 eeprom 136 void tea5767_auto_search() 137 { 138 TEA_DAT dat; 139 unsigned long Khz; 140 unsigned char if_counter; 141 unsigned char channel = 0; 142 Khz = TEA5767_MIN_KHZ; 143 144 //清液晶屏 145 lcd1602_clear(); 146 147 dat = tea5767_search(Khz); 148 149 //檢測信號是否滿足要求 150 while(dat.st1 != (dat.st1 | (1<<6))) 151 { 152 //if count 在 0x31 ~ 0x3e 之間 153 if_counter = (dat.st3 & 0x7f); 154 if((0x31 < if_counter) && (0x3e > if_counter)) 155 { 156 //比較leve 電平確認是否收到台 實際測試使用此數 不會漏台 157 if((dat.st4>>4) > 10) 158 { 159 Khz = tea5767_pll_to_Khz(dat); 160 161 save_eeprom(Khz, channel); 162 channel++; 163 } 164 } 165 166 //顯示當前頻率 167 sohw_search(Khz, channel); 168 169 //計算搜到台的頻率 加上10Khz 后重新搜索 實際測試使用此數 不會漏台 170 Khz += 10; 171 dat = tea5767_search(Khz); 172 } 173 } 174 175 //細致的搜台 176 void tea5767_tiny_auto_search() 177 { 178 TEA_DAT dat; 179 unsigned long Khz; 180 unsigned char channel = 0; 181 Khz = TEA5767_MIN_KHZ; 182 //Khz = 100000; 183 184 //清液晶屏 185 lcd1602_clear(); 186 187 //擦除eeprom 188 eeprom_erase(1); 189 190 while(Khz <= TEA5767_MAX_KHZ) 191 { 192 dat = tea5767_set_receiver(Khz); 193 //比較leve 電平確認是否收到台 實際測試使用此數 不會漏台 194 if((dat.st4>>4) > 8) 195 { 196 //存儲電台 197 save_eeprom(Khz, channel++); 198 } 199 200 //顯示當前頻率 201 sohw_search(Khz, channel); 202 //頻率由低到高 每次增加10Khz 203 Khz += 100; 204 } 205 } 206 207 208 void sohw_search(unsigned long Khz, unsigned char channel) 209 { 210 unsigned char high, low; 211 lcd1602_pos(0); 212 lcd1602_write_data('S'); 213 lcd1602_write_data('e'); 214 lcd1602_write_data('a'); 215 lcd1602_write_data('r'); 216 lcd1602_write_data('c'); 217 lcd1602_write_data('h'); 218 lcd1602_write_data(':'); 219 //輸出頻率 如果是 100M 以下第1位為空 220 high = Khz/1000; 221 low = Khz%1000/100; 222 if(high>= 100) 223 { 224 lcd1602_write_data(num_to_str(high/100)); 225 } 226 else 227 { 228 lcd1602_write_data(' '); 229 } 230 lcd1602_write_data(num_to_str(high%100/10)); 231 lcd1602_write_data(num_to_str(high%10)); 232 lcd1602_write_data('.'); 233 lcd1602_write_data(num_to_str(low)); 234 lcd1602_write_data('M'); 235 lcd1602_write_data('h'); 236 lcd1602_write_data('z'); 237 238 //顯示收到的頻道 239 lcd1602_pos(40); 240 lcd1602_write_data('C'); 241 lcd1602_write_data('h'); 242 lcd1602_write_data('a'); 243 lcd1602_write_data('n'); 244 lcd1602_write_data('n'); 245 lcd1602_write_data('e'); 246 lcd1602_write_data('l'); 247 lcd1602_write_data(':'); 248 249 lcd1602_write_data(num_to_str(channel / 10)); 250 lcd1602_write_data(num_to_str(channel % 10)); 251 } 252 253 //存儲電台 254 void save_eeprom(unsigned long Khz, unsigned char channel) 255 { 256 TEA_CH ch; 257 ch.high = Khz/1000; 258 ch.low = Khz%1000/100; 259 eeprom_prog(channel*2, ch.high); 260 eeprom_prog(channel*2+1, ch.low); 261 } 262 263 //設定ch 264 unsigned long set_ch(unsigned char ch_num) 265 { 266 unsigned long Khz; 267 TEA_CH ch; 268 ch.high = eeprom_read(ch_num*2); 269 ch.low = eeprom_read(ch_num*2+1); 270 //合並為 Khz 271 Khz = ch.high*100; //直接使用 *1000 會計算錯誤 分為2部正確 272 Khz *= 10; 273 Khz += ch.low*100; 274 275 //設定接收頻率 276 tea5767_set_receiver(Khz); 277 278 //清液晶屏 279 lcd1602_clear(); 280 281 //顯示頻道信息 282 lcd1602_pos(0); 283 lcd1602_write_data('C'); 284 lcd1602_write_data('h'); 285 lcd1602_write_data(':'); 286 287 //頻道數從 0 開始計 288 lcd1602_write_data(num_to_str(ch_num / 10)); 289 lcd1602_write_data(num_to_str(ch_num % 10)); 290 291 lcd1602_pos(8); 292 if(ch.high>= 100) 293 { 294 lcd1602_write_data(num_to_str(ch.high/100)); 295 } 296 else 297 { 298 lcd1602_write_data(' '); 299 } 300 lcd1602_write_data(num_to_str(ch.high%100/10)); 301 lcd1602_write_data(num_to_str(ch.high%10)); 302 lcd1602_write_data('.'); 303 lcd1602_write_data(num_to_str(ch.low)); 304 lcd1602_write_data('M'); 305 lcd1602_write_data('h'); 306 lcd1602_write_data('z'); 307 308 return Khz; 309 }
eeprom.c
1 #include "eeprom.h" 2 3 /* 執行完操作以后安全鎖 */ 4 void eeprom_lock_ISP() 5 { 6 ISP_CONTR = 0; 7 ISP_CMD = 0; 8 ISP_TRIG = 0; 9 ISP_ADDRH = 0xff; 10 ISP_ADDRL = 0xff; 11 } 12 13 /* 擦除指定地址所在的整個扇區 */ 14 void eeprom_erase(unsigned int addr) 15 { 16 addr += BASE_ADDR; 17 18 //發送地址 19 ISP_ADDRH = addr >> 8; 20 ISP_ADDRL = addr; 21 22 //發送解鎖命令 23 ISP_CONTR = En_Wait_ISP; 24 25 //發擦除命令 26 ISP_CMD = CMD_Erase; 27 28 //發送觸發命令 29 ISP_TRIG = 0x46; 30 ISP_TRIG = 0xB9; 31 32 //最后鎖定 ISP 仿誤操作 33 eeprom_lock_ISP(); 34 } 35 36 unsigned char eeprom_read(unsigned int addr) 37 { 38 addr += BASE_ADDR; 39 40 //發送地址 41 ISP_ADDRH = addr >> 8; 42 ISP_ADDRL = addr; 43 44 //發送解鎖命令 45 ISP_CONTR = En_Wait_ISP; 46 47 //發讀命令 48 ISP_CMD = CMD_Read; 49 50 //發送觸發命令 51 ISP_TRIG = 0x46; 52 ISP_TRIG = 0xB9; 53 54 //最后鎖定 ISP 仿誤操作 55 eeprom_lock_ISP(); 56 57 return ISP_DATA; 58 } 59 60 void eeprom_prog(unsigned int addr, unsigned char dat) 61 { 62 addr += BASE_ADDR; 63 64 //發送要保存的數據 65 ISP_DATA = dat; 66 67 //發送地址 68 ISP_ADDRH = addr >> 8; 69 ISP_ADDRL = addr; 70 71 //發送解鎖命令 72 ISP_CONTR = En_Wait_ISP; 73 74 //發編程命令 75 ISP_CMD = CMD_Prog; 76 77 //發送觸發命令 78 ISP_TRIG = 0x46; 79 ISP_TRIG = 0xB9; 80 81 //最后鎖定 ISP 仿誤操作 82 eeprom_lock_ISP(); 83 }
最后,在簡單說下,自動搜台 和 手動搜台的區別。
自動搜台特點:
1,設一個 LEVE 值后,當到這個值的時候,能自動停止,但是靈活性只有3種,不夠靈活。
2,能增長到最高頻率時,停止
3,只能用 TEA5756_HLSI
自動搜台流程:
1,設定 好 SM 位 和 SSL 后
2,設一個頻率
3,TEA5767 就會自動向上 或 向下 查找,直到 確認收到了信號,就停止 有標識位, 同時比較是否到了最終端,108M
4,程序需要判斷,有信號的標識位, 108M 到終點的標識位2個。
5,程序也要比較ADC 電平,再次確認是否搜到了台
手動搜台特點:
1,控制靈活,但要自行控制以上參數。程序編寫簡單。
手動搜台流程:
1,寫入一個頻率
2,讀取ADC 比較高於某個值時就表示收到了台
3,自行判斷,頻率范圍