当前位置:首页 >> 信息与通信 >>

基于单片机的RDS接收控制设计







要 .................................................. 1

Abstract ................................................ 2 第1章 方案设计 .......................

................. 2

1.1 基于 nRF401 的接收控制设计 ........................ 2 1.2 基于 RDS 功能的接收控制设计 ....................... 4 第2章 接收模块设计 .................................... 6

2.1 接收模块硬件设计 ................................. 6 2.1.1 FM 接收电路设计 ............................. 6 2.1.2 单片机控制电路的设计 ........................ 7 2.1.3 音频放大电路的设计 .......................... 8 2.2 接收部分软件设计 ................................. 9 2.2.1 QN8035 的源程序 ............................. 9 2.2.2 12864 源程序 ................................21 2.2.3 单片机控制 QN8035 的程序 .....................32 2.2.4 I2C 总线的源程序 ............................36 结 论 ..................................................43

参考文献 ................................................44 附 录 ..................................................45





现代社会中,基于单片机的 RDS 接收控制模块是我们在生活、学习等各方面普遍接触 到的商品的重要组成部分之一,如无线对讲机、收音机等。它有效地为我们的生活提供了 便利。 本 文 主要 设 计 一个 基 于 单片 机 的 RDS 接 收 控制 模 块 。采用 嵌 入 式处 理 器 芯 片 STC89C52RC 控制,使用 FM 接收芯片 QN8035 接收信息。本系统设计分为硬件设计和软件设 计两部分。硬件设计部分包含 FM 接收电路设计、单片机控制电路设计和音频放大电路设 计;软件设计部分包含 QN8035 的源程序、12864 源程序、单片机控制 QN8035 的程序和 I2C 总线的源程序。然后通过 Protel 进行仿真,实现本次系统设计的功能。 关键词: 单片机 STC89C52RC 、QN8035、接收控制、RDS 功能

1

Abstract
In modern society, based on single chip microcomputer RDS reception control module is our life, study and so on various aspects in common exposure to one of the important component of the goods, such as radio, radio, etc. It effectively provides a convenience to our lives. In this paper, we design a RDS receiver based on single-chip microcomputer control module. Using embedded processor chip STC89C52RC control, the use of FM receiver chip QN8035 receiving information. This system is divided into hardware design and software design two parts. Hardware design part contains an FM receiver circuit design, the MCU control circuit design, and audio amplifier circuit design; Software design section contains QN8035 source program, 12864 source program, single-chip microcomputer control QN8035 programs and source code of the I2C bus. Then simulation by Protel, can realize the function of the system design. Keywords: SCM ,STC89C52RC and QN8035, receives the control, the RDS function

2

基于单片机的 RDS 接收控制设计
第1章 方案设计
1.1 基于 nRF401 的接收控制设计
nRF401 是 Nordic 公司研制的单片 UHF 无线收发芯片, 工作在 433MHz ISM Industrial, ( Scientific and Medical)频段。它采用 FSK 调制解调技术,抗干扰能力强,并采用 PLL 频率合成技术,频率稳定性好,发射功率最大可达 10dBm,接收灵敏度最大为-105dBm, 数据传输速率可达 20Kbps,工作电压在+3~5V 之间。nRF401 无线 nRF401 无线收发芯片所 需外围元件较少,并可直接接单片机串口。 nRF401 芯片内包含有发射功率放大器(PA)、低噪声接收放大器(LNA)、晶体振荡 器(OSC)、锁相环(PLL)、压控振荡器(VCO)、混频器(MIXFR)、解调器(DEM)等 电路。在接收模式中,nRF401 被配置成传统的外差式接收机,所接收的射频调制的数字信 号被低噪声效大器放大,经混频器变换成中频,放大、滤波后进入解调器,解调后变换成 数字信号输出(DOUT 端)。在发射模式中,数字信号经 DIN 端输入,经锁相环和压控振荡 器处理后进入到发射功率放大器射频输出。由于采用了晶体振荡和 PLL 合成技木,频率稳 定性极好;采用 FSK 调制和解调,抗干扰能力强。 50Ω 的单端天线通过差分转换匹配网络连接到 nRF401 的 ANT1 和 ANT2 引脚。使用 nRF401 的 ANT1 和 ANT2 引脚是接收时低噪声接收放大器 LNA 的输入, 以及发送时发射功率 放大器 PA 的输出。连接 nRF401 的天线可以以差分方式连接到 nRF401,一个 50Ω 的单端 天线也可以通过一个差分转换匹配网络连接到 nRF401。环形天线 nRF401,整个环形天线 可以做在 PCB 上,对比传统的鞭状天线或单端天线,不仅节省空间和生产成本,机构上也 更稳固可靠,图 1.1 基于 nRF401 无线收发设计的框图。

话 筒

前置放大

nRF401

功效

单片机

图 1.1 基于 nRF401 无线数字对讲系统设计的框图
3

1.2 基于 RDS 功能的接收控制设计
调频发射部分:与 QN8035 接收机模块配对的是以 QN8027 芯片为中心的发射模块,可 以实现音频和 RDS 的发射。 单片机我们使用开发板,这样解决了我们编写软件时没有硬件的问题,并且开发板每 个管脚可以用跳线引出,接线方便。 QN8027 是一颗高性能、低能耗、全功能的立体声调频发射单芯片,主要适用于便携式 音频和视频播放器、汽车配件、手机及 GPS 个人导航设备等。QN8027 集成了完整的 FM 发 射、空台扫描,以及天线自动调谐等功能。先进的数字架构使变量输入增益可编程,可选 预加重,提供了精确的 MPX 立体声编码,基于 PLL 的低噪声调制以及纯净的频谱。 QN8027 凭借其体积小巧,所需外部元件数量少,并且支持多个时钟频率,很容易被 集成到多种小型低功耗便携式应用中。QN8027 集成了稳压器使它可以直接连接电池,并 提供高电源纹波抑制比可以更高效地抑制噪声。具有低功耗待机模式,能充分延长电池使 用时间。所有管脚都有静电保护。QN8027 应用高可靠性的 CMOS 制程制造。 调频接收机:在众多的 FM 接收模块中我们选择使用 QN8035 芯片为中心的模块。 QN8035 是一颗高性能、低能耗、全功能的立体声调频接收单芯片,主要适用于手机、MP3 播放器及便携式收音机等。QN8035 支持 RDS/RBDS 数据接收。接收射频信号首先由一个低 噪声放大器,然后向下转换为一个中间频率传给正交混频器。为了改善音质,抑制噪音, 正交混频器可被编程在高端或低端注入。每个通道使用滤波器抑制干扰信号。它还可以接 收 RDS 信息,内容可以通过 LCD 显示。高功率 32Ω 负载音频输出,直接耳机驳接,无需外 接音频放大,图 1.2 基于 QN8027、QN8035 无线收发系统设计框图。

话 筒

前置放大

8027

FM 射频放 大

单片机

4

8035

音频功放

扬声器

单片机

图 1.2 基于 QN8027、QN8035 无线数字对讲系统设计框图

综上比较两种方案,考虑系统的便携性,效率以及成本问题 nRF401 虽然可以符合设 计要求,所需外围较少,可直接与串口相接,但是 QN8035 开发板每个管脚可以用跳线引 出,接线方便,QN8027 应用高可靠性的 CMOS 制程制造,更加适合本设计的要求,因此采用 方案二来实现这个系统。

5

第2章

接收模块设计

2.1 接收模块硬件设计
2.1.1 FM 接收电路设计
QN8035 是一颗高性能、低能耗、全功能的立体声调频接收单芯片,主要适用于手机、 MP3 播放器及便携式收音机等。QN8035 支持 RDS/RBDS 数据接收。支持全球 FM 波段发射; 76 MHz ~108 MHz 全波段调步长 50/100/200 kHz;50/75μ s 去加重;易于集成;小封装, 提供 2.5 x2.5mm QFN16 和 3x3 MSOP10 两种封装;支持 32.768 kHz ~MHz 的时钟输入; I2C 控制接口;低功耗;典型值 13 mA;VCC: 2.7~5.0V,集成稳压器,可直连电池;VIO: 1.6~3.6V, VCC: 2.7~5.0V;省电和待机模式;极小关断电流;提供 1.6~3.6V 数字接口; 高性能;优越的灵敏度,优于 1.5μ VEMF;63dB 立体声信噪比, 0.03% THD;集成了音频 处理 (SNC, HCC, SM);改进了自动搜台功能;L/R 声道分离 45dB;RDS/RBDS 接收机;支 持美国和欧洲的数据服务;稳健运行;在-250C 到 +850C 范围内运;所有输入和输出管 脚都有静电保护。图 2.1.1 是 QN8035FM 接收电路框图。

图 2.1.1 QN8035 接收电路内部图
6

2.1.2 单片机控制电路的设计
STC89C52 单片机具有以下特点:增强型 8051 单片机,6 时钟/机器周期和 12 时钟/ 机器周期可以任意 选择, 指令代码完全兼容传统 8051.[2]; 工作电压: 5.5V~3.3V (5V 单 片机)/3.8V~2.0V(3V 单片机);工作频率范围:0~40MHz,相当于普通 8051 的 0~ 80MHz, 实际工作 频率可达 48MHz; 用户应用程序空间为 8K 字节; 片上集成 512 字节 RAM; 通用 I/O 口(32 个),复位后为:P0/P1/P2/P3 是准双向口/弱上拉, P0 口是漏极开路 输出,作为总线扩展用时,不用加上拉电阻,作为 I/O 口用时,需加上拉电阻;ISP(在 系统可编程)/IAP(在应用可编程),无需专用编程器,无 需专用仿真器,可通过串口 (RxD/P3.0,TxD/P3.1)直接下载用户程 序,数秒即可完成一片;具有 EEPROM 功能;具 有看门狗功能;共 3 个 16 位定时器/计数器。即定时器 T0、T1、T2;外部中断 4 路,下 降沿中断或低电平触发电路,Power Down 模式可 由外部中断低电平触发中断方式唤醒; 通用异步串行口(UART),还可用定时器软件实现多个 UART;工作温度范围:-40~+85℃ (工业级)/0~75℃(商业级);PDIP 封装。图 2.1.2 是 STC89C52RC 控制 QN8035 的电 路图。

图 2.1.2

STC89C52 控制 QN8035 电路

7

2.1.3 音频放大电路的设计
由于 QN8035 与 QN8027 均是双信道接收机,所以音频放大的时候也要选择双信道音 频放大。 音频放大电路主要用来向扬声器中送去驱动信号, 它可以将功率进行放大。 2.1.3 图 是音频放大电路。

图 2.1.3 音频放大电路

8

2.2 接收部分软件设计
2.2.1 QN8035 的源程序
/******************QN8035.h****************/ #ifndef __QN8035_H__ #ifndef __QN8035_H__ #include <stdio.h> #define uint unsigned int #define uchar unsigned char

/******一级指令*********/ #define clear #define turn_on #define turn_off #define action_on 3 #define action_off #define send_rds 5 #define change_fm 6 /******从机开关二级指令***********/ #define area1 #define area2 #define area3 #define area4 #define area5 #define area6 #define area7 #define area8 #define area9 1 2 3 4 5 6 7 8 9 4 0 1 2

#define area_all 10 #define area_single 11
9

/******从机动作二级指令***********/ #define yu_cun #define man_set #define feng_mq #define ji_dq #define zhi_sd uint fm=9000; uchar vol=0x0f; sbit RSSI_ZS = P3^7; 2 1 //接收频率初始值 //音量初始值最大 5 4 3

bit Mute_flag=1; bit RDS_flag=0; extern uchar Init_Riss; extern uchar Init_Volue; extern uchar defu_mute; //定义操作 QN8035 数据区 unsigned char idata QN8035_Send[9]; unsigned char idata QN8035_Read[9]; unsigned char idata buffer[36]={0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9}; void QN8035_delay(unsigned int count); void QN8035_Init(void); bit RDS_check(); void RDS_Init(); unsigned char QN8035_Rssi_Read(); void QN8035_Write_Freq(unsigned int Frequnt); void QN8035_Vol_Set(unsigned char ucLevel); void QN8035_Mute_ctr(bit Mute_flag); void QN8035_set(); unsigned int QN8035_Auto_Seek(unsigned int Str_Freq); unsigned int QN8035_Auto_Seek_ll(unsigned int Str_Freq); #endif
10

//RDS 标志位

/********************************************************* 函数功能:定义软件延时 函数名:QN8035_delay 入口参数:count 出口参数:无 **********************************************************/ void QN8035_delay(unsigned int count) { unsigned int i,j; for(i=count; i>0; i--) for(j=111; j>0; j--); } /********************************************************* 函数功能:初始化 QN8035 模块 函数名:QN8035_Init 入口参数:无 出口参数:无 **********************************************************/ void QN8035_Init(void) { QN8035_Send[0x00] = 0x00; QN8035_Send[0x01] = 0x81; I2C_Data_Write(0x20, &QN8035_Send[0], 2); QN8035_Send[0x00] = 0x18; QN8035_Send[0x01] = 0x10; I2C_Data_Write(0x20, &QN8035_Send[0], 2); QN8035_Send[0x00] = 0x2F; QN8035_Send[0x01] = 0x90; I2C_Data_Write(0x20, &QN8035_Send[0], 2); QN8035_Send[0x00] = 0x40;
11

QN8035_Send[0x01] = 0x01; I2C_Data_Write(0x20, &QN8035_Send[0], 2); QN8035_Send[0x00] = 0x46; QN8035_Send[0x01] = 0x05; QN8035_Send[0x02] = 0xD0; QN8035_Send[0x03] = 0xA8; I2C_Data_Write(0x20, &QN8035_Send[0], 4); QN8035_Send[0x00] = 0x4A; QN8035_Send[0x01] = 0x18; I2C_Data_Write(0x20, &QN8035_Send[0], 2); QN8035_Send[0x00] = 0x14; QN8035_Send[0x01] = 0xC6; QN8035_Send[0x02] = 0x00; QN8035_Send[0x03] = 0x02; QN8035_Send[0x04] = 0x20; I2C_Data_Write(0x20, &QN8035_Send[0], 5); QN8035_Send[0x00] = 0x00; QN8035_Send[0x01] = 0x51; I2C_Data_Write(0x20, &QN8035_Send[0], 2); QN8035_delay(1000); QN8035_Send[0x00] = 0x00; QN8035_Send[0x01] = 0x01; I2C_Data_Write(0x20, &QN8035_Send[0], 2); QN8035_Send[0x00] = 0x00; QN8035_Send[0x01] = 0x11; QN8035_Send[0x02] = 0x49; I2C_Data_Write(0x20, &QN8035_Send[0], 3); QN8035_delay(279); } /*********************************************************
12

函数功能:读取 Rssi 信号,用来控制静音,防止噪音,也可实现电源控制 函数名:QN8035_Rssi_Read 入口参数:无 出口参数:QN8035_Read[0] **********************************************************/ unsigned char QN8035_Rssi_Read() { I2C_selset_Read(0x20, 0x03, &QN8035_Read[0], 1); //,读取 Rssi 信号,用来控 制静音,防止噪音 //return QN8035_Read[0]; if((QN8035_Read[0]-46) >= Init_Riss) 度,开启声音,(启动电源) { if(defu_mute)//静音时能 { QN8035_Send[0x00] = 0x14; QN8035_Send[0x01] = 0x40|Init_Volue; I2C_Data_Write(0x20, &QN8035_Send[0], 2); RSSI_ZS=0;defu_mute=0; } } else//--------------------------------------------//信号强度不够, 使能静音, 关闭电源! { if(!defu_mute) //没有静音 { QN8035_Send[0x00] = 0x14; QN8035_Send[0x01] = 0xC6; I2C_Data_Write(0x20, &QN8035_Send[0], 2); RSSI_ZS=1;defu_mute=1;
13

//理想的信号强

} } } /********************************************************* 函数功能:向 QN8035 模块写入一个频率,手动设置频率 函数名:QN8035_Write_Freq 入口参数:Frequnt 需要写入的频率 出口参数:无 **********************************************************/ void QN8035_Write_Freq(unsigned int Frequnt) { QN8035_Send[0x00] = 0x07; QN8035_Send[0x01] = (Frequnt - 6175)/5; I2C_Data_Write(0x20, &QN8035_Send[0], 2); QN8035_Send[0x00] = 0x0A; QN8035_Send[0x01] = ((Frequnt - 6175)/5 >> 8) | 0x60; I2C_Data_Write(0x20, &QN8035_Send[0], 2); } /********************************************************* 函数功能:软件音量调节 函数名:QN8035_Write_Freq 入口参数:ucLevel 需要写入的声音大小 出口参数:无 **********************************************************/ void QN8035_Vol_Set(unsigned char ucLevel) { QN8035_Send[0x00]=0x14; QN8035_Send[0x01]=0x40|(ucLevel); I2C_Data_Write(0x20, &QN8035_Send[0], 2); }
14

/********************************************************* 函数功能:手动静音控制,如果 Mute_flag=1 静音,否则不静音, 函数名:QN8035_Mute_ctr 入口参数:Mute_flag 出口参数:无 **********************************************************/ void QN8035_Mute_ctr(bit Mute_flag) { if(Mute_flag) { QN8035_Send[0x00] = 0x14; QN8035_Send[0x01] = 0xC6; I2C_Data_Write(0x20, &QN8035_Send[0], 2); } else { QN8035_Send[0x00] = 0x14; QN8035_Send[0x01] = 0x40|vol; I2C_Data_Write(0x20, &QN8035_Send[0], 2); } } /********************************************************* 函数功能? RDS 初始化

**********************************************************/ void RDS_Init() { QN8035_Send[0x00] = 0x17; QN8035_Send[0x01] = 0xA0; I2C_Data_Write(0x20, &QN8035_Send[0], 2); QN8035_Send[0x00] = 0x00; //开启 RDS
15

//RDS 使能

QN8035_Send[0x01] = 0x19; I2C_Data_Write(0x20, &QN8035_Send[0], 2); } bit RDS_check() { uchar i,j,k; uchar bian=0,old=0; i=150; while(i--) { I2C_selset_Read(0x20,0x13,&QN8035_Read[0x00],1); QN8035_Read[0x00]&=0x9f; if(QN8035_Read[0x00]==16||QN8035_Read[0x00]==144) { if(old!=QN8035_Read[0x00]) { bian++; old=QN8035_Read[0x00]; } Delay_1ms(5); } } /***************观测用******************/ //wr_string(0,2,"变化次数:"); //wr_int(5,2,bian); if(bian>3) return 1; else return 0; } void QN8035_set() { bit flag; QN8035_Init(); QN8035_Write_Freq(fm); //QN8035 初始化 //设置频率
16

RDS_Init(); //flag=RDS_check(); //if(flag){ //else Mute_flag=0;

//RDS 初始化

RDS_flag=1; RDS_flag=0;

} }

{Mute_flag=1;

//QN8035_Mute_ctr(Mute_flag); QN8035_Vol_Set(vol); } /********************************************************* 函数功能:QN8035 模块实现自动搜索 函数名:unsigned int QN8035_Auto_Seek(unsigned int Str_Freq) 入口参数:Str_Freq 出口参数:搜索到的频率 **********************************************************/ unsigned int QN8035_Auto_Seek(unsigned int Str_Freq) { unsigned int scan_freq,Read_Freq,Send_freq; unsigned char Freq_H; scan_freq=Str_Freq; rescan: QN8035_Send[0x00] = 0x08; QN8035_Send[0x01] = (scan_freq - 6175)/5; QN8035_Send[0x02] = 0x9D; QN8035_Send[0x03] = ((scan_freq - 6175)/5 >> 6) | 0x70; I2C_Data_Write(0x20, &QN8035_Send[0], 4); QN8035_Send[0x00] = 0x01; QN8035_Send[0x01] = 0x7D; //75 I2C_Data_Write(0x20, &QN8035_Send[0], 2); QN8035_Send[0x00] = 0x00; QN8035_Send[0x01] = 0x10; I2C_Data_Write(0x20, &QN8035_Send[0], 2);
17

//设置音量

QN8035_Send[0x00] = 0x00; QN8035_Send[0x01] = 0x12; I2C_Data_Write(0x20, &QN8035_Send[0], 2); QN8035_delay(500); I2C_selset_Read(0x20, 0x0a, &QN8035_Read[0], 1); Freq_H=(QN8035_Read[0]&0x03); I2C_selset_Read(0x20, 0x07, &QN8035_Read[0], 1); Read_Freq=Freq_H*256+QN8035_Read[0]; Send_freq=(Read_Freq)*5+6175; if(Send_freq==10800) { scan_freq=8760; goto rescan; } else { return (Send_freq); } } //*************************************************************************** ******** //------------------------------QN8035 程序完 --------------------------------------//*************************************************************************** ******** /********************************************************* 函数功能:QN8035 模块实现自动搜索,反向收缩 函数名:unsigned int QN8035_Auto_Seek(unsigned int Str_Freq) 入口参数:Str_Freq 出口参数:搜索到的频率
18

**********************************************************/ unsigned int QN8035_Auto_Seek_ll(unsigned int Str_Freq) { unsigned int scan_freq,Read_Freq,Send_freq; unsigned char Freq_H; scan_freq=Str_Freq; rescan_ll: QN8035_Send[0x00] = 0x08; QN8035_Send[0x01] = (scan_freq - 6175)/5; QN8035_Send[0x02] = 0x0D; //9d

QN8035_Send[0x03] = ((scan_freq - 6175)/5 >> 6) | 0x60; I2C_Data_Write(0x20, &QN8035_Send[0], 4); QN8035_Send[0x00] = 0x01; QN8035_Send[0x01] = 0x59; I2C_Data_Write(0x20, &QN8035_Send[0], 2); QN8035_Send[0x00] = 0x00; QN8035_Send[0x01] = 0x10; I2C_Data_Write(0x20, &QN8035_Send[0], 2); QN8035_Send[0x00] = 0x00; QN8035_Send[0x01] = 0x12; I2C_Data_Write(0x20, &QN8035_Send[0], 2); QN8035_delay(500); I2C_selset_Read(0x20, 0x0a, &QN8035_Read[0], 1); Freq_H=(QN8035_Read[0]&0x03); I2C_selset_Read(0x20, 0x07, &QN8035_Read[0], 1); Read_Freq=Freq_H*256+QN8035_Read[0]; Send_freq=(Read_Freq)*5+6175; if(Send_freq<=8800) { scan_freq=10850;
19

goto rescan_ll; } else { return (Send_freq); } } //*************************************************************************** ******** //------------------------------QN8035 程序完 ----------------------------------//*************************************************************************** ********

20

2.2.2 12864 源程序
/******************12864c.h****************/ //设定 wr 为 P24 //设定 en 为 P23 //在 main()中开输出 //******************************************** #define uint unsigned int #define uchar unsigned char #ifndef __12864C_H__ #define __12864C_H__

#define uint unsigned int #define uchar unsigned char #include<intrins.h> sbit RS=P2^3; sbit SID=P2^4; sbit SCLK=P2^5; sbit RST=P3^7; sbit PSB=P2^6; //sbit PSB=P0^4; //sbit RST=P0^3; //在此设置输入端口 *************************************************************************** #define LCD_SID1 SID=1 #define LCD_SID0 SID=0 #define LCD_SCLK1 SCLK=1 #define LCD_SCLK0 SCLK=0 #define x1 #define x2 #define y 0x80 0x88 0x80
21

//片选(正) //RW(SID) //E(SCLD) //复位(正) //(负:串行模式)

//WR 做数据传输使用 sid

//EN 当做串行时钟使用 sclk

#define comm #define dat

0 1

code uchar num[]={"0123456789"}; #define CPU_F ((double)16000000)//cpu frequency8000000 #define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0)) #define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0))//wr_lcd(1,data)/wr_lcd(0,addre ss) void clr_34(); void Delay180us(); void Delay_1ms(uchar del); void lcd_set(); void wr_lcd(uchar dat_comm,uchar content); 数据 content 数据 void init_lcd(void); void clrram(); //初始化 //清屏 //写数据/地址或命令 dat_comm 为

void clr_lcd(uchar x,uchar y0,uchar length); //清除 lcd 任意位置字符 从 y0 行, 的第 x 个位置(1、16),清除 length 个字符 void lcd_xy(uchar x,uchar y0); void wr_data(uchar x,uchar y0,uchar data0 ); void wr_string(uchar x,uchar y0,uchar *p); void wr_int2(uchar x,uchar y0,uint NUM); void wr_int(uchar x,uchar y0,uint NUM); void wr_xxx(uchar hang,uchar lie,int sign); void wr_long(uchar x,uchar y0,long NUM); void wr_float(uchar x,uchar y0,float NUM); #endif void clr_34() { clr_lcd(0,2,16);
22

//定位光标 // //

//写入 4 为整形数据

//写入 xx.xxx 型浮点数

clr_lcd(0,3,16); } void lcd_set() { //配置液晶引脚工作在串口模式下 RS=1; PSB=0; RST=1; } void Delay180us() { unsigned char i, j; _nop_(); _nop_(); i = 6; j = 93; do { while (--j); } while (--i); } /******************************************************************** * 名称 : Delay_1ms() //@22.1184MHz ***********************************************************************/ void Delay_1ms(uchar del) { uchar i, j,k; //@11.0592MHz

for(k=0;k<del;k++) { _nop_();
23

i = 2; j = 199; do { while (--j); } while (--i); } } void init_lcd(void)//***************************************init_lcd() { wr_lcd(comm,0x30);//8-BIT 控制接口,基本指令集动作 wr_lcd(comm,0x01);//清除显示 全屏清除 Delay_1ms(1); wr_lcd(comm,0x06);//光标右移,AC 自动加一,整体显示不移动 wr_lcd(comm,0x0c);//整体显示 ON,光标显示 OFF,光标位置不反白闪 } void clrram()//************************* *********************clrram() { wr_lcd(comm,0x30);//8-BIT 控制接口,基本指令集动作 wr_lcd(comm,0x01);//清除显示 Delay180us(); } //-----------清除 lcd 任意位置字符-------*/ //--------position 为任一位置的起始地址--*/ //--length 为长度,取值为 1-64---/若只清一行最大为 16// void clr_lcd(uchar x,uchar y0,uchar length)//**********************clr_lcd() { uint i; uchar pos; switch(y0)
24

//y0 为行号

{ case 0: pos=0x80+x;break; case 1: pos=0x90+x;break; case 2: pos=0x88+x;break; case 3: pos=0x98+x;break; default: break; } wr_lcd(comm,pos); 据长度次 for(i=0;i<length;i++) { wr_lcd (dat,0x20);//填充空格 } }

//x 为行的光标位置 一行有 16 个 //行列转换为地址

//写零清除数据 在 Pos 位置写 写数

void wr_lcd(uchar dat_comm,uchar content)//********************* 写 命 令 或 数 据 **********// { // uchar a,i,j; Delay180us(); a=content; LCD_SCLK0; //en=0; LCD_SID1; //wr=1 要写的数据

for(i=0;i<5;i++) //数据时序*****************8 { LCD_SCLK1; LCD_SCLK0; } LCD_SID0; LCD_SCLK1; LCD_SCLK0; //wr=0 //en=1 //en=0
25

if(dat_comm) LCD_SID1; else LCD_SCLK1; LCD_SCLK0; LCD_SID0; LCD_SCLK1; LCD_SCLK0; for(j=0;j<2;j++)//************8 次循环写写一字节数据 { for(i=0;i<4;i++) { if(a&0x80) LCD_SID1; else LCD_SID0; a=a<<1; LCD_SCLK1; LCD_SCLK0; } LCD_SID0; for(i=0;i<4;i++) { LCD_SCLK1; LCD_SCLK0; } } } //*************************************************************************** ***************** void lcd_xy(uchar x,uchar y0)////***************************(用于中间调用****
26

LCD_SID0;

//时钟

写地址**********// { uchar pos=0; switch(y0) { case 0: pos=0x80+x;break; case 1: pos=0x90+x;break; case 2: pos=0x88+x;break; case 3: pos=0x98+x;break; default:break; } wr_lcd(comm,pos); } //*************************************************************************** ************* void wr_data(uchar x,uchar y0,uchar data0 )//***********************显示单个字 符**********// { uchar pos=0; switch(y0) { case 0: pos=0x80+x;break; case 1: pos=0x90+x;break; case 2: pos=0x88+x;break; case 3: pos=0x98+x;break; default:break; } wr_lcd(comm,pos);//comm 为零。函数意思是移动光标到此 wr_lcd(dat,data0);//写入这个数据 }
27

dat 和 comm 是 1,0 的标志

//**X 取值 0-3,Y 取值 0-7 void wr_string(uchar x,uchar y0,uchar *p) //************************ 写 字 符 串 ********//// { uchar pos=0;//初始化 uchar cnt=0;//传递过来的是指针 ,cnt 为偏移量,然后一个字符一个字符的写入。 switch(y0) { case 0: pos=0x80+x;break; case 1: pos=0x90+x;break; case 2: pos=0x88+x;break; case 3: pos=0x98+x;break; default: break; } wr_lcd(comm,pos);//写地址 while(*(p+cnt)!='\0') { wr_lcd(dat,*(p+cnt));//写数据 cnt++; }; } //************************************************************************* void wr_int2(uchar x,uchar y0,uint NUM) //**********************************************整型数据显示 { uchar a_SHOW[3] a_SHOW[0]=(NUM/10)%10+'0';//shi a_SHOW[1]=NUM%10+'0';//ge a_SHOW[2]='\0'; wr_string(x,y0,a_SHOW);
28

} //************************************************************************* void wr_int(uchar x,uchar y0,uint NUM) //**********************************************整型数据显示 { uchar a_SHOW[5]; a_SHOW[0]=(NUM/1000)%10+'0';//qian a_SHOW[1]=(NUM/100)%10+'0' ;//bai a_SHOW[2]=(NUM/10)%10+'0';//shi a_SHOW[3]=NUM%10+'0';//ge a_SHOW[4]='\0'; wr_string(x,y0,a_SHOW); } /******************************************************************** * 名称 : wr_xx.x(uchar hang,uchar lie,int sign) * 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符显示"b" ,调用该函数如 下 L1602_char(1,5,'b') * 输入 : 行,列,需要输入 1602 的数据 * 输出 : 无 ***********************************************************************/ void wr_xxx(uchar hang,uchar lie,int sign) { uchar a[6]; a[0]=sign/10000+'0'; a[1]=sign/1000%10+'0'; a[2]=sign/100%10+'0'; a[3]='.'; a[4]=sign/10%10+'0'; // a[5]=sign/10%10+'0';
29

a[5]= '\0'; wr_string(hang,lie,a); } //************************************************************************* void wr_long(uchar x,uchar y0,long NUM) //**********************************************整型数据显示 { uchar a_SHOW[9]; a_SHOW[0]=(NUM/10000000)%10+'0';//qian a_SHOW[1]=(NUM/1000000)%10+'0';//qian a_SHOW[2]=(NUM/100000)%10+'0' ;//bai a_SHOW[3]=(NUM/10000)%10+'0';//shi a_SHOW[4]=(NUM/1000)%10+'0';//qian a_SHOW[5]=(NUM/100)%10+'0' ;//bai a_SHOW[6]=(NUM/10)%10+'0';//shi a_SHOW[7]=NUM%10+'0';//ge a_SHOW[8]='\0'; wr_string(x,y0,a_SHOW); } //************************************************************************* voidwr_float(ucharx,uchary0,float NUM) //********************************8 浮点 型数据显示 { uchar a_SHOW[7]; long int t; t=NUM*1000; a_SHOW[0]=(t/10000)%10+'0';//shi a_SHOW[1]=(t/1000)%10+'0' ;//ge a_SHOW[2]='.'; //

a_SHOW[3]=(t/100)%10+'0';//shi fen a_SHOW[4]=(t/10)%10+'0'; //bai fen
30

a_SHOW[5]=t%10+'0'; a_SHOW[6]='\0'; wr_string(x,y0,a_SHOW); }

//qian fen

31

2.2.3 单片机控制 QN8035 的程序
#ifndef __eeprom_H__ #define __eeprom_H__ #define uint unsigned int #define uchar unsigned char #define ENABLE_IAP #define IAP_ADDRESS #define CMD_IDLE #define CMD_READ #define CMD_PROGRAM #define CMD_ERASE uint data_eep; void Delay(uchar n); void IapIdle(); uint IapReadByte(uint addr); void IapProgramByte(uint addr,uint da); void IapEraseSector(uint addr); void wr_ee_datas (uint addr, uchar *p, uchar count); void read_ee_datas (uint addr, uchar *p, uchar count); #endif void Delay(uchar n) { uchar i,j; for(i=n;n--;n>0) ; for(j=110;j--;j>0); } /*----------------------------------------关闭 IAP -------------------------------------------*/
32

0x81 0X0800 0 1 2 3

void IapIdle() { IAP_CONTR =0; IAP_CMD IAP_TRIG IAP_ADDRH IAP_ADDRL } /*----------------------------------------从 IAP EEPROM 读取一个字节 -------------------------------------------*/ uint IapReadByte(uint addr) { uint data_eep; IAP_CONTR =ENABLE_IAP; IAP_CMD IAP_ADDRL =CMD_READ; =addr; =0; =0; =0X80; =0;

IAP_ADDRH =addr>>8; EA=0; IAP_TRIG IAP_TRIG _nop_(); _nop_(); EA = 1; data_eep = IAP_DATA; return data_eep; } /*----------------------------------------写一个字节到 IAP EEPROM 区 -------------------------------------------*/
33

=0X46; =0Xb9;

void IapProgramByte(uint addr,uint data_eep) { IAP_CONTR =ENABLE_IAP; IAP_CMD IAP_ADDRL =CMD_PROGRAM; =addr;

IAP_ADDRH =addr>>8; IAP_DATA= data_eep; EA=0; IAP_TRIG IAP_TRIG _nop_(); _nop_(); EA = 1; } /*----------------------------------------IAP EEPROM 扇区擦除 -------------------------------------------*/ void IapEraseSector(uint addr) { IAP_CONTR = ENABLE_IAP; IAP_CMD = CMD_ERASE; IAP_ADDRL = addr; IAP_ADDRH = addr>>8; //IAP_DATA = data_eep; //EA=0; IAP_TRIG = 0X46; IAP_TRIG = 0Xb9; _nop_(); _nop_(); }
34

=0X46; =0Xb9;

/******************************************* 写多个数据到 E2 中 *******************************************/ void wr_ee_datas (uint addr, uchar *p, uchar count) { for ( ; count > 0; count --) { IapProgramByte(addr++ , *p); p ++; } } /******************************************* 读多个数据到指定的数组中 *******************************************/ void read_ee_datas (uint addr, uchar *p, uchar count) { for ( ; count > 0; count --) { *p = IapReadByte(addr ++); //*p = data_eep; p ++; } }

35

2.2.4 I2C 总线的源程序

/******************I2C.h****************/ #ifndef __I2C_H__ #ifndef __I2C_H__ #define uint unsigned int #define uchar unsigned char #include <intrins.h> //引脚定义 sbit I2C_SCL=P3^2; sbit I2C_SDA=P3^1; /*********************************************************************/ //定义空指令 #define NOP() _nop_(),_nop_(),_nop_(),_nop_(),_nop_(),_nop_(),_nop_(),_nop_() void I2C_Start(void); void I2C_Stop(void); bit I2C_ReadAck(void); void I2C_SendAck(void); void I2C_SendNoack(void); void I2C_Send_Byte(unsigned char sendbyte); unsigned char I2C_Receive_Byte(void); void I2C_Data_Write(unsigned char Mac_ID, unsigned char *ptr,unsigned char num); void I2C_Data_Read(unsigned char Mac_ID, unsigned char *ptr,unsigned char num); void I2C_selset_Read(unsigned char Mac_ID, unsigned char Addr, unsigned char *ptr, unsigned char num); #endif /*********************************************************************/ //启动 I2C 总线 void I2C_Start(void)

36

{ I2C_SDA=1; NOP(); I2C_SCL=1; NOP();NOP();NOP();NOP();NOP(); I2C_SDA=0; NOP();NOP();NOP();NOP();NOP(); I2C_SCL=0; } /*********************************************************************/ //停止 I2C 总线 void I2C_Stop(void) { I2C_SCL=0; I2C_SDA=0; NOP(); I2C_SCL=1; NOP();NOP();NOP();NOP();NOP(); I2C_SDA=1; NOP();NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP();NOP(); I2C_SCL=0; I2C_SDA=0; } /*********************************************************************/ //单片机接收应答位(返回 0 表示应答) bit I2C_ReadAck(void) { unsigned char ccsj = 220; I2C_SCL=0;
37

I2C_SDA=1; NOP(); I2C_SCL=1; while(I2C_SDA) { ccsj--; if (ccsj == 0) { I2C_Stop(); return 0; } } I2C_SCL=0; return 1; } /*********************************************************************/ //单片机发送应答信号 void I2C_SendAck(void) { I2C_SCL=0; I2C_SDA=0; NOP();NOP();NOP();NOP();NOP(); I2C_SCL=1; NOP();NOP();NOP();NOP();NOP(); I2C_SCL=0; } /*********************************************************************/ //单片机发送非应答信号 void I2C_SendNoack(void) {
38

I2C_SCL=0; I2C_SDA=1; NOP();NOP(); I2C_SCL=1; NOP();NOP(); I2C_SCL=0; } /*********************************************************************/ //单片机发送一个字节 void I2C_Send_Byte(unsigned char sendbyte) { unsigned char count = 8; while( count-- ) { I2C_SCL = 0; NOP(); if ( sendbyte &0x80 ) I2C_SDA =1; else I2C_SDA =0; NOP(); I2C_SCL = 1; NOP(); sendbyte <<= 1; } I2C_ReadAck(); } /*********************************************************************/ //单片机接收一个字节 unsigned char I2C_Receive_Byte(void)
39

{ unsigned char count = 8, data_buffer; I2C_SDA = 1; while ( count--) { I2C_SCL =0; NOP();NOP(); I2C_SCL =1; NOP();NOP(); data_buffer <<= 1; if ( I2C_SDA ) data_buffer++; } return (data_buffer); } /*********************************************************************/ //单片机发送数据 //向指定的硬件地址写 count 个数据 void I2C_Data_Write(unsigned char Mac_ID, unsigned char *ptr,unsigned char num) { I2C_Start(); I2C_Send_Byte( Mac_ID ); while(num--) { I2C_Send_Byte( *(unsigned char*)ptr ); ((unsigned char*)ptr)++; } I2C_Stop(); } /*********************************************************************/
40

//单片机读取数据 //向指定的硬件地址读取 count 个数据 void I2C_Data_Read(unsigned char Mac_ID, unsigned char *ptr,unsigned char num) { I2C_Start(); I2C_Send_Byte( Mac_ID | 0x01); while(num--) { *ptr = I2C_Receive_Byte(); if(num != 0) I2C_SendAck(); ptr++; }

I2C_SendNoack(); I2C_Stop(); } /*********************************************************************/ //单片机读取数据 //向指定的硬件地址,指定的地址,读取 count 个数据 void I2C_selset_Read(unsigned char Mac_ID, unsigned char Addr, unsigned char *ptr, unsigned char num) { I2C_Start(); I2C_Send_Byte( Mac_ID); I2C_Send_Byte( Addr ); I2C_Start(); I2C_Send_Byte( Mac_ID | 0x01 ); while(num--) {
41

*ptr = I2C_Receive_Byte(); if(num != 0) I2C_SendAck(); ptr++; } I2C_SendNoack(); I2C_Stop(); } /*******************************************over***************************** **********************************/ /*******************************************over**************************

42





本系统设计主要采用 QN825、 QN8027 为核心芯片安装调试,对所学过的单片机原理, 本系统具有成本低、体积小、低功耗、符合电池供电需求、集成度高、无需微调外部元件、 外围元件小、加工容易、数据传输率高、传输时间短、接口简单、可以与廉价单片机接口 的特点。接收芯片 QN8025 接收信号之后通过 STC89C52 的控制在显示芯片 12864 上显示 出来,从而完成智能数据的采集及无线传输功能系统。另外,由于系统采用了 STC89C52 为单片机控制芯片,单片机具有体积小、功耗低、控制能力强、扩展灵活、微型化、和使 用方便、等优点可广泛应用于控制系统,数据采集系统等等。设计中遇到的关键问题是芯 片的选择、接收芯片跟单片机的硬件连接和软件程序设计的问题。

43

参考文献
[1] 郭理豪. 基于无线网络的多媒体监控系统的研究与设计[D]. 浙江工业大学 2009. [2] 刘晓兰.基于 MPEG 的多媒体数字视频监控采集子系统的研究与设计[D]山东大 学.2005 [3] 杜彩侠. 基于 ARM 的无线对讲系统的设计与实现[D]. 武汉理工大学, 2012 [4] 李江南. 一种基于 C8051F330 的网络对讲机[D]. 电子科技大学, 2007 . [5] 张迪强. 基于 MCF5213 的对讲机系统的设计与实现[D]. 电子科技大学, 2009 . [6] 邱吉刚,林孝康. 基于 ARM 内核的民用数字对讲机系统的设计[J]. 微计算机信息, 2006,(29) [7] 徐贵森,刘鑫,谭学治. 浅谈无线电对讲机模拟转数字[J]. 移动通信, 2009,(06) [8] 李龙文. 《小功率集成开关稳压器》 电子技术应用 [9] 刘晔 常弘. 《电工电子技术导论》 西安交通大学 2009 [10]解沅清,解月珍. 《通信电子线路》人民邮电出版社,1994 年 [11] 陈永等. 《集群移动通信机和对讲机原理、使用及维修手册》[M]. 北京:电子 工业出版社,1997. [12] 陈永甫, 谭秀华. 《理代通信系统和信息网》 [M]. 北京: 电子工业出版社, 1996. [13]伍蔡伦,李世义,王宝全 《全球定位系统信号接收机射频模块的设计》[J]., 国 外电子元器件,2006 年 第 01 期 [14]苗汇静,宋宜华,宋刚 《实用新型 VHF 无线双向对讲机》【J】电声技术 1998 [15] Troels Pedersen Estimation Contributions in Radio Channel Sounding, Modeling, and

44





45


相关文章:
基于单片机的RDS接收控制设计
Keywords: SCM ,STC89C52RC and QN8035, receives the control, the RDS function 2 基于单片机的 RDS 接收控制设计第1章 方案设计 1.1 基于 nRF401 的接收...
毕业设计(论文)-基于单片机的智能家居控制系统设计
毕业设计(论文)-基于单片机的智能家居控制系统设计_信息与通信_工程科技_专业资料...因其布线简单、 功能灵活, 扩展容易而被人们广泛接受和应用。 至今, X-10 ...
基于单片机的继电器控制设计
本科生毕业论文基于单片机的继电器控制设计 Design of 学生姓名 所在专业 所在班级 申请学位 指导教师 答辩时间 职称 2015 年 5 月 30 日 relay control based on...
基于单片机的自动门控制系统设计 毕业论文
基于单片机的自动门控制系统设计 毕业论文_电子/电路_工程科技_专业资料。常州机电...具体在数控机床中,伺服系统 接收数控系统发出的位移、速度指令,经变换、放大与...
基于单片机的电动机正反转控制设计
淮南师范学院 2013 届本科毕业论文 基于单片机的电动机正反转控制设计学生:xxx(指导教师:xxx) (xxxxxx 电气信息工程学院) 摘要:基于单片机的基本理论,本文设计了一...
基于单片机的数据采集与传输系统设计
整 个系统由三个部分构成: 系统的主要部分是卫星及地面控制设备, 关口站, ...基于单片机的温度检测与无线传输系统由多个传感器节点和数据接收端两 个部份成,...
基于单片机的自动售货机设计
基于单片机的自动售货机系统设计 售货机的工作原理...1 .2 自动售货过程的控制系统简述控制系统由...位双向 I/O 口,P1 口缓冲器能接收输出 4TTL 门...
基于单片机控制的汽车倒车系统设计
基于单片机控制的汽车倒车系统设计_电子/电路_工程科技_专业资料。毕业设计任务书...测距系统主要由超声波发 射电路、超声波接收检测电路和显示电路组成。设计利用 ...
课程设计 单片机控制的收音机
本次设计利用 STC89C52 单片机控制收音机模块 PL102BA-S(基于 SI4730 芯片)...内置数字频率调谐和 DSP 解码器,支持数字音频输出及 RDS 接收功能。支持 I2C ...
更多相关标签:
单片机控制系统设计 | 单片机温度控制器设计 | 单片机交通灯控制设计 | 单片机霓虹灯控制设计 | rds管理控制台 | rds控制台 | 单片机串口接收字符串 | 单片机红外接收程序 |