RDA5807的数控收音机要点

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

摘要
现在人们常使用的收音机为手动调频收台,使用较为麻烦,而且由于接收灵敏度不高,所接收的频段较窄。

为了解决这些问题,本次采用RDA5807收音模块与单片机相结合,实现FM收音并显示频率。

单片机自20世纪70年代问世以来,以极其高的性能价格比受到人们的重视和关注,所以应用很广,发展很快。

单片机的特点是体积小、集成度高、重量轻、抗干扰能力强,对环境要求不高,价格低廉,可靠性高,灵活性好,开发较为容易,所以本次采用stc89c52单片机。

此外,RDA5807模块具有65-108MHz全球FM接收频段相容的效果,具备噪声消除、软静音、低音增强,灵敏度高、噪声小、抗干扰能力强等功能,还可以具备频率显示功能,所以使用本模块很容易实现。

目录
引言 (1)
1.方案选择 (2)
1.1方案一………………………………………………………….. 1.2方案二………………………………………………………….
1.3方案确定………………………………………………………
2.系统方案设计及各模块原理……………………………………
2.1STC89C52核心模块………………………………………………
2.1.1STC89C52单片机简介…………………………………………
2.1.2STC89C52主要性能………………………………………….
2.2RDA5807模块…………………………………………………….
2.2.1RDA5807模块特点……………………………………………
2.2.2RDA5807模块使用…………………………………………
2.3显示模块……………………………………………………………
2.3.11602液晶简介…………………………………………………
2.3.21602引脚说明…………………………………………………
2.4IIC通信…………………………………………………………
2.4.1IIC简介……………………………………………………….
2.4.2IIC时序………………………………………………………
3系统程序设计……………………………………………………
4印刷电路板的设计与制作………………………………………
4.1印刷电路板的布线设计…………………………………………
4.2印刷电路板的制作………………………………………………
5 电路板的调试……………………………………………………
6 结论………………………………………………………………
谢辞……………………………………………………………….
参考文献………………………………………………………………
附录…………………………………………………………………
引言
本设计研究FM收音机分为硬件电路和程序设计两个方面。

从硬件电路来说,主要是实现所需电压值、稳压、搜台、控制和频率显示等方面;从系统程序来说,主要是通过软件来实现RDA5807模块的功能,使用IIC总线方式调台,并且得到当前的频率,处理并实现频率转换、显示。

1.方案选择
1.1方案一
使用分立元件来搭接电路,实现模块的功能,收发信号,对信号调频或者调幅,从而得到可以处理的信号,实现收听功能。

由于本方案,调试极为复杂,很难成功,而且接收频率范围小,工作也很不稳定,很容易受外界影响。

1.2方案二
采用RDA5807模块,实现接收信号,并处理功能,并于单片机相结合,实现数控,操作简单。

由于RDA5807模块高度的集成,很多功能都集成在内部,所以工作稳定,不容易受外界影响,而且需要的外部东西少,使用IIC总线与单片机相连接,使用的线少,模块简单,操作方便,并且接收频率范围很广。

2系统方案设计及各模块原理
本方案采用STC89C52单片机与RDA模块连接,从而实现数控收音机,STC89C52单片机在这方面的设计为我们提供了极大的方便,用它实现的好处在于,外围电路极其简单,另外在STC89C52单片机的编程方面又提供及其便利的编程环境。

外围电路的设计包括两大部分,分别是液晶的显示和键盘控制电路的设计。

这里采用一个复位按键,来实现对RDA5807模块的初始化。

设计的特点是全面采用数字电路方案,因而工作稳定可靠。

利用单片机控制管理,使设置及调整操作准确。

STC89C52最小系统原理图
RDA5807收音模块
2.1 STC89C52核心模块
STC89C52是STC公司生产的一种低功耗、高性能CMOS8位微控制器,具有8K 在系统可编程Flash存储器。

STC89C52使用经典的MCS-51内核,但做了很
多的改进使得芯片具有传统51单片机不具备的功能。

在单芯片上,拥有灵巧的8 位CPU 和在系统可编程Flash,使得STC89C52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。

具有以下标准功能: 8k字节Flash,512字节RAM, 32 位I/O 口线,看门狗定时器,内置4KB EEPROM,MAX810复位电路,3个16 位定时器/计数器,4个外部中断,一个7向量4级中断结构(兼容传统51的5向量2级中断结构),全双工串行口。

另外 STC89C52 可降至0Hz 静态逻辑操作,支持2种软件可选择节电模式。

2.1.1 STC89C52单片机简介
其引脚结构及说明如下:
VCC : 电源
GND: 地
P0 口:P0口是一个8位漏极开路的双向I/O口。

作为输出口,每位能驱动8个TTL逻辑电平。

对P0端口写“1”时,引脚用作高阻抗输入。

当访问外部程序和数据存储器时,P0口也被作为低8位地址/数据复用。

在这种模式下,P0具有内部上拉电阻。

在 flash编程时,P0口也用来接收指令字节;在程序校验时,输出指令字节。

程序校验时,需要外部上拉电阻。

P1 口:P1 口是一个具有内部上拉电阻的8 位双向I/O 口,p1 输出缓冲器能驱动4 个TTL 逻辑电平。

对P1 端口写“1”时,内部上拉电阻把端口拉高,此时可以作为输入口使用。

作为输入使用时,被外部拉低的引脚由于内部电阻的原因,将输出电流(IIL)。

此外,P1.0和P1.2分别作定时器/计数器2的外部计数输入(P1.0/T2)和时器/计数器2的触发输入P1.1/T2EX)。

在flash编程和校验时,P1口接收低8位地址字节。

P2 口:P2 口是一个具有内部上拉电阻的8 位双向I/O 口,P2 输出缓冲器能驱动4 个TTL 逻辑电平。

对P2 端口写“1”时,内部上拉电阻把端口拉高,此时可以作为输入口使用。

作为输入使用时,被外部拉低的引脚由于内部电阻的原因,将输出电流(IIL)。

在访问外部程序存储器或用16位地址读取外部数据存储器(例如执行MOVX @DPTR)时,P2 口送出高八位地址。

在这种应用中,P2 口使用很强的内部上拉发送1。

在使用8位地址(如MOVX @RI)访问外部数据存储器时,P2口输出P2锁存器的内容。

在flash编程和校验时,P2口也接收高8位地址字节和一些控制信号。

P3 口:P3 口是一个具有内部上拉电阻的8 位双向I/O 口,p2 输出缓冲器能驱动4 个TTL 逻辑电平。

对P3 端口写“1”时,内部上拉电阻把端口拉高,此时可以作为输入口使用。

作为输入使用时,被外部拉低的引脚由于内部电阻的原因,将输出电流(IIL)。

P3口亦作为AT89S52特殊功能(第二功能)使用,如下所示。

P3.0 RXD(串行输入口)
P3.1 TXD(串行输出口)
INT(外部中断0)
P3.2 0
INT(外部中断1)
P3.3 1
P3.4 T0(记时器0外部输入)
P3.5 T1(记时器1外部输入)
P3.6 WR(外部数据存储器写选通)
P3.7 RD(外部数据存储器读选通)
在flash编程和校验时,P3口也接收一些控制信号。

RST: 复位输入。

晶振工作时,RST脚持续2 个机器周期高电平将使单片机复位。

看门狗计时完成后,RST 脚输出96 个晶振周期的高电平。

特殊寄存器AUXR(地址8EH)上的DISRTO位可以使此功能无效。

DISRTO默认状态下,复位高电平有效。

ALE/PROG:地址锁存控制信号(ALE)是访问外部程序存储器时,锁存低8 位地址的输出脉冲。

在flash编程时,此引脚(PROG)也用作编程输入脉冲。

在一般情况下,ALE 以晶振六分之一的固定频率输出脉冲,可用来作为外部定时器或时钟使用。

然而,特别强调,在每次访问外部数据存储器时,ALE脉冲将会跳过。

如果需要,通过将地址为8EH的SFR的第0位置“1”,ALE操作将无效。

这一位置“1”,ALE 仅在执行MOVX 或MOVC指令时有效。

否则,ALE 将被微弱拉高。

这个ALE 使能标志位(地址为8EH的SFR的第0位)的设置对微控制器处于外部执行模式下无效。

PSEN:外部程序存储器选通信号(PSEN)是外部程序存储器选通信号。

当AT89S52从外部程序存储器执行外部代码时,PSEN在每个机器周期被激活两次,而在访问外部数据存储器时,PSEN将不被激活。

EA/VPP:访问外部程序存储器控制信号。

为使能从0000H 到FFFFH的外部程序存储器读取指令,EA必须接GND。

为了执行内部程序指令,EA应该接VCC。

在flash编程期间,EA也接收12伏VPP电压。

XTAL1:振荡器反相放大器和内部时钟发生电路的输入端。

XTAL2:振荡器反相放大器的输出端。

2.1.2 STC89C52主要性能
--与MCS-51单片机产品兼容
--8K字节在系统可编程Flash存储器
--1000次擦写周期
--全静态操作:0Hz~33Hz
--三级加密程序存储器
--32个可编程I/O口线
--三个16位定时器/计数器
--八个中断源
--全双工UART串行通道
--低功耗空闲和掉电模式
--掉电后中断可唤醒
--看门狗定时器
--双数据指针
--掉电标志位
--内带2K字节EEPROM存储空间
--可直接使用串口下载
--512字节数据存储空间
2.2 RDA5807模块
“RRD-102V2.0”立体声收音模块( FM Stereo radio Module)高灵敏度、低功耗、超小体积的调频立体声收音模组。

采用RDA Microelectronics的RDA5807M(或RDA5802NM),此电路外围元件少、噪声系数极小。

具有体积小、低功耗、低成本、应用简单、使用范围广等优点。

是一款简单易用且具极高性价比的单芯片FM立体声收音模组。

模块的引脚及外围电路图
2.2.1 RDA5807模块特点
A、采用通用的102BC模块的封装,用户可直接替换使用,无需更改电路设计。

B、灵敏度高、噪声小、抗干扰能力强、外接元件极少、体积小(11*11.2MM Max)、使用极其简单。

C、 76-108MHz全球FM频段兼容(包括日本76-91MHz和欧美87.5-108.5MHz)。

D、 I2C串行数据总线接口通讯,支持外部基准时钟输入方式。

E、完全整合的COMS工艺单晶片集成电路,功耗极小。

F、内置高精度A/D(模数转换器)及数字频率合成器。

G、内置LDO调整、低功耗、超宽电压使用范围(2.7-3.6VDC)。

H、内置噪声消除、软静音、低音增强电路设计。

I、高功率32Ω负载音频输出,直接耳机驳接,无需外接音频驱动放大。

J、应用简便、成本低,性价比高。

2.2.2 RDA5807模块使用说明
A、模块供电滤波电容设计是应尽量靠近模块电源输入脚。

B、I2C DAT, CLK芯片内部已经包含47k的上拉电阻;
C、如用耳机的地线做天线,则参照上图应用大原理图
D、为了模块能良好的可靠的工作,FM模块供电电压一般应大于2.7V以上。

E、此模块内部已集成LDO,电源输入端可使用简单的LC电源滤波网络即可。

F、使用时应做好ESD静电防护工作。

G、模块可串电容后直接驱动32ohm耳机,如需推动更大功率喇叭请外加功放;
2.3显示模块
显示模块由1602液晶电路构成。

2.3.1 1602液晶简介
1602液晶是工业字符型液晶,能够同时显示16x02即32个字符。

(16列2行)。

2.3.2 1602引脚说明
1602字符型LCD通常有14条引脚线或16条引脚线的LCD,多出来的2条线是背光电源线。

VCC(15脚)和地线GND(16脚),其控制原理与14脚的LCD完全一样,其中:
1602液晶引脚说明
2.4IIC通信
根据RDA5807模块的要求,使用IIC通信,与单片机相连接,实现数控。

2.4.1 IIC简介
IIC是由菲利浦半导体公司在八十年代初设计出来的,主要是用来连接整体电路(ICS) ,IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实施数据传输的控制源。

这种方式简化了信号输总线。

IIC串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。

所有接到IIC总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。

2.4.3 IIC时序
在IIC总线传输过程中,将两种特定的情况定义为开始和停止条件:当SCL 保持“高”时,SDA由“高”变为“低”为开始条件;当SCL保持“高”且SDA 由“低”变为“高”时为停止条件。

开始和停止条件均由主控制器产生。

使用硬件接口可以很容易地检测到开始和停止条件,没有这种接口的微机必须以每时钟周期至少两次对SDA取样,以检测这种变化。

SDA线上的数据在时钟“高”期间必须是稳定的,只有当SCL线上的时钟信号为低时,数据线上的“高”或“低”状态才可以改变。

输出到SDA线上的每个字节必须是8位,每次传输的字节不受限制,但每个字节必须要有一个应答ACK。

如果一接收器件在完成其他功能(如一内部中断)前不能接收另一数据的完整字节时,它可以保持时钟线SCL为低,以促使发送器进入等待状态;当接收器准备好接受数据的其它字节并释放时钟SCL后,数据传输继续进行。

I2C数据总线传送时序。

数据传送具有应答是必须的。

与应答对应的时钟脉冲由主控制器产生,发送器在应答期间必须下拉SDA线。

当寻址的被控器件不能应答时,数据保持为高并使主控器产生停止条件而终止传输。

在传输的过程中,在用到主控接收器的情况下,主控接收器必须发出一数据结束信号给被控发送器,从而使被控发送器释放数据线,以允许主控器产生停止条件。

3系统程序设计
程序框图
具体程序详见附录
4.1 印刷电路板的布线设计
此过程是用Altium Designer 来完成。

布线设计按以下流程实现。

图4.1 布线流程
布线时的注意事项:
(1)在摆放元件时先按原理图摆放,再细调位置。

(2)所用的为单面板,故布线时应在底层Button Layer上。

(3)布线区域应在禁止布线层Keep Out Layer上圈定。

(4)两根线之间的距离不能太小,在线拐弯处不能用成直角,一般用45度
角为宜。

(5)线宽设置在0.8—1.0毫米,在一些拐角的地方还可以适当地补线,以
防止腐蚀的时候将线腐蚀掉或是因为线太细而对电路造成不良的影响。

4.2印刷电路板的制作
首先,把PCB给打印出来,用砂纸把铜板除去外层的氧化铜,在预热熨斗后,把PCB放到板上,把线熨至铜板上。

待铜板冷却后再将纸从铜板撕下,检查铜板上有没有断线的地方,若有少量,则用油性笔把线给补上!太多的话就用砂纸把线去除之后再重新烫过。

然后,尽快把熨好的铜板放到氯化铁溶液中。

第三,腐蚀完后先进行打孔,再把铜线上的墨去掉。

这样打孔比较方便。

第四,就是装元件,在此过程中一定要注意有正负极性的元件,比如LED 灯、电解电容等。

最后进行焊接。

5 电路板的调试
调试过程是一个非常重要的环节,这是整个电路板成功与否的关键。

首先应断开电源,用数字万用表认真检查电路连线是否有误,是否有短路或者断路和虚焊等的现象。

经过初步检查以后,方可接通电源。

此时还不应该把芯片装上。

接上电源时应该明确电源的正负极性,切不可接反,一接反则马上可能会出现烧毁重要元件的情况!时刻用手触摸各元件有没有发热现象,并注意其是否冒烟等。

待过一段时间稳定后,如没有出现不良的现象,则电路基本上正常,可依次用数字万用表检查各点的工作电压情况,各点工作稳定,并且确认芯片插座两端的电压符合芯片的工作电压时,则可以关闭电源,把芯片装上。

附录
主程序
#include "reg52.h"
#include "intrins.h"
#include "lcd.h"
#include "IIC.h"
#include "delay.h"
sbit K1 = P2^0;
sbit K2 = P2^1;
sbit K3 = P2^2;
sbit K4 = P2^3;
unsigned long frequency;
// RDA5807 寄存器
unsigned char RDA_reg_data[8] =
{
0xd0,0x00, // 02H
0x00,0x00, // 03H
0x00,0x40, // 04H
0x90,0x88, // 05H
};
unsigned char code cdis1[ ] = {"FM cui's RADIO "}; unsigned char code cdis2[ ] = {"FM VOL "};
char code reserve[3]_at_ 0x3b; //保留0x3b开始的3个字节连续写寄存器子函数
void RDA5807_write_reg(void)
{
uchar i;
I2C_start();
// 收音模块写入操作
I2C_write_byte(0x20);
// 寄存器连续写操作
for(i=0; i<8; i++)
{
I2C_write_byte(RDA_reg_data[i]);
}
I2C_stop();
}
连续读寄存器子函数
void RDA5807_read_reg(uchar *reg_buf) {
I2C_start();
// 收音模块读取操作
I2C_write_byte(0x21);
// 寄存器连续读操作
reg_buf[0] = I2C_read_byte(I2C_ACK); reg_buf[1] = I2C_read_byte(I2C_ACK); reg_buf[2] = I2C_read_byte(I2C_ACK); reg_buf[3] = I2C_read_byte(I2C_NACK);
I2C_stop();
}
模块上电初始化子函数
void RDA5807_power(void)
{
delayms(50);
// 发送软件复位指令
RDA_reg_data[0] = 0x00;
RDA_reg_data[1] = 0x02;
RDA5807_write_reg();
delayms(10);
// 收音模块默认参数
RDA_reg_data[0] = 0xd0;
RDA_reg_data[1] = 0x01;
RDA5807_write_reg();
功能描述:收音模块自动寻台模式
void RDA5807_FM_seek(void)
{
uint chan;
uchar reg_data[4] = {0x00, 0x00, 0x00, 0x00};
RDA_reg_data[3] &= ~(1 << 4); //调谐禁用
// 内部自动寻台使能
RDA_reg_data[0] |= (1 << 0); //SEEK位置1 RDA5807_write_reg();
// 等待STC 标志置位
while(0 == (reg_data[0] & 0x40))
{
delayms(20);
// 读取内部状态
RDA5807_read_reg(reg_data);
}
// 获取当前工作频点
chan = reg_data[0] & 0x03;
chan = reg_data[1] | (chan << 8);
chan = chan << 6;
// 保存当前工作频点
RDA_reg_data[2] = (chan >> 8) & 0xff;
RDA_reg_data[3] = (chan & 0xff);
}
频率显示子函数
void show_frequency(void)
{
unsigned char i,display[5];
unsigned int temp;
temp = (RDA_reg_data[2]*256)+(RDA_reg_data[3]&0xc0); //计算 temp = temp>>6;
frequency = (unsigned long)(100*temp+87000)/100;
for(i=0; i<5; i++) // 清显存单元
display[i] = 0x00;
display[0] = (frequency)/1000 ; //数据转换
display[1] = (frequency%1000)/100;
display[2] = (frequency%100)/10;
display[3] = 0x2e; //小数点
display[4] = (frequency%10);
if(display[0] == 0)
{
display[0] = display[1]+0x30;
display[1] = display[2]+0x30;
display[2] = display[3];
display[3] = display[4]+0x30;
display[4] = 0x20;
}
else
{
display[0] += 0x30;
display[1] += 0x30;
display[2] += 0x30;
display[4] += 0x30;
}
lcd_pos_xy(3,2); //频率显示
lcd_wdat(display[0]);
lcd_wdat(display[1]);
lcd_wdat(display[2]);
lcd_wdat(display[3]);
lcd_wdat(display[4]);
}
音量显示子函数
void show_volume()
{
unsigned char temp,display[2];
temp = RDA_reg_data[7] & 0x0f; //取音量值
display[0] = temp/10;
display[1] = temp%10;
if(display[0] == 0) //如果高位为0
{
display[0] = display[1]; //低位显存内容进入高位显存 display[1] = 0x20; //低位不显示
}
else
{
display[1] += 0x30;
}
display[0] += 0x30;
lcd_pos_xy(13,2); //音量值显示
lcd_wdat(display[0]);
lcd_wdat(display[1]);
}
主函数
void main(void)
{
P0 = 0xff;
P1 = 0xff;
P2 = 0xff;
lcd_init();
lcd_w_string(0,1,cdis1,0);
lcd_w_string(0,2,cdis2,0);
RDA5807_power();
while(1)
{
if(K1 == 0)
{
delayms(20);
if(K1 == 0)
{
RDA_reg_data[0] |= (1 << 1); //SEEK UP
RDA5807_FM_seek();
while(K1 == 0);
}
}
if(K2 == 0)
{
delayms(20);
if(K2 == 0)
{
RDA_reg_data[0] &= ~(1 << 1); //SEEK DOWN RDA5807_FM_seek();
while(K2 == 0);
}
}
if(K3 == 0)
{
delayms(20);
if(K3 == 0)
{
if((RDA_reg_data[7] & 0x0f) < 0x0f) {
RDA_reg_data[0] = 0xd0;
RDA_reg_data[1] = 0x01;
RDA_reg_data[3] &= ~(1 << 4);
RDA_reg_data[7]++; // 音量递增 RDA5807_write_reg();
while(K3 == 0);
}
}
}
if(K4 == 0)
{
delayms(20);
if(K4 == 0)
{
if((RDA_reg_data[7] & 0x0f) > 0x00) {
RDA_reg_data[0] = 0xd0;
RDA_reg_data[1] = 0x01;
RDA_reg_data[3] &= ~(1 << 4);
RDA_reg_data[7]--; // 音量递减 RDA5807_write_reg();
while(K4 == 0);
}
}
}
show_volume();
show_frequency();
}
}
Lcd程序
#include "reg52.h"
#include "intrins.h"
#include "lcd.h"
#include "delay.h"
#define uchar unsigned char
#define uint unsigned int
#define DATA_PORT P1
sbit LCD_RS = P2^6;
sbit LCD_RW = P2^5;
sbit LCD_EN = P2^4;
检查LCD忙状态
lcd_busy为1时,忙,等待。

lcd-busy为0时,闲,可写指令与数据。

bit lcd_busy()
{
bit result;
LCD_RS = 0;
LCD_RW = 1;
LCD_EN = 1;
delayNOP();
result = (bit)(DATA_PORT&0x80);
LCD_EN = 0;
return(result);
}
写指令数据到LCD
RS=L,RW=L,E=高脉冲,D0-D7=指令码。

Check=1,进行忙检测。

void lcd_wcmd(uchar cmd, bit Check)
{
if(Check)
while(lcd_busy());
LCD_RS = 0;
LCD_RW = 0;
LCD_EN = 0;
delayNOP();
DATA_PORT = cmd;
delayNOP();
LCD_EN = 1;
delayNOP();
LCD_EN = 0;
}
写显示数据到LCD
RS=H,RW=L,E=高脉冲,D0-D7=数据。

void lcd_wdat(uchar dat)
{
while(lcd_busy()); //进行忙检测
LCD_RS = 1;
LCD_RW = 0;
LCD_EN = 0;
DATA_PORT = dat;
delayNOP();
LCD_EN = 1;
delayNOP();
LCD_EN = 0;
}
LCD初始化设定
void lcd_init()
{
delayms(50);
lcd_wcmd(0x38,0); //16*2显示,5*7点阵,8位数据
delayms(5);
lcd_wcmd(0x38,0); //不进行忙检测,强制执行。

delayms(5);
lcd_wcmd(0x38,0);
delayms(5);
lcd_wcmd(0x38,1); //进行忙检测
delayms(5);
lcd_wcmd(0x0c,1); //显示开,关光标
delayms(5);
lcd_wcmd(0x06,1); //移动光标
delayms(5);
lcd_wcmd(0x01,1); //清除LCD的显示内容
delayms(5);
}
设定显示位置
void lcd_pos_xy(uchar pos_x,uchar pos_y)
{
uchar pos_temp;
pos_temp=pos_x & 0x0f;
pos_y &= 0x0f;
if(pos_y==0x01)
pos_temp |= 0x80;
else
if(pos_y==0x02)
pos_temp |= 0xc0;
lcd_wcmd(pos_temp,1);
}
写字符串子函数
void lcd_w_string(uchar pos_x,uchar pos_y,uchar code *str,uint times)
{
uchar m;
lcd_pos_xy(pos_x,pos_y); //设定起始位置 for(m=0; m<16; m++)
{
lcd_wdat(str[m]);
delayms(times);
}
}
IIC程序
#include "reg52.h"
#include "delay.h"
#include "IIC.h"
sbit SDA = P3^0;
sbit SCL = P3^1;
启动子程序
在 SCL 高电平期间 SDA 发生负跳变
void I2C_start()
{
SDA = 1;
SCL = 1;
delayNOP();
SDA = 0;
delayNOP();
SCL = 0;
}
停止子函数
在 SCL 高电平期间 SDA 发生正跳变
void I2C_stop()
{
SDA = 0;
SCL = 1;
delayNOP();
SDA = 1;
delayNOP();
}
发送一个字节子程序
unsigned char I2C_write_byte(unsigned char indata) {
unsigned char i, ack;
// I2C 发送8 位数据
for (i=0; i<8; i++)
{
// 高在前低在后
if (indata & 0x80)
SDA = 1;
else
SDA = 0;
// 发送左移一位
indata <<= 1;
delayNOP();
SCL = 1;
delayNOP();
SCL = 0;
}
// 设置SDA为输入
SDA =1;;
delayNOP();
// 读取从机应答状态
SCL = 1;
delayNOP();
if(SDA)
{
ack = I2C_NACK;
}
else
{
ack = I2C_ACK;
}
SCL = 0;
return ack;
}
读一个字节子程序
unsigned char I2C_read_byte(unsigned char ack) {
unsigned char i, data1 = 0;
// SDA 设置输入方向
SDA = 1;
// I2C 接收8位数据
for(i = 8; i > 0; i--)
{
data1 <<= 1;
SCL = 1;
delayNOP();
// 高在前低在后
if (SDA)
{
data1++;
}
SCL = 0;
delayNOP();
}
// 主机发送应答状态
if(ack == I2C_ACK)
SDA = 0;
else
SDA = 1;
delayNOP();
SCL = 1;
delayNOP();
SCL = 0;
return data1;
}
Delay延迟程序#include "delay.h"
us延时子程序
void delayNOP()
{
_nop_();_nop_();_nop_();_nop_();
}
ms延时子程序
void delayms( unsigned int ms)
{
unsigned char k;
while(ms--)
{
for(k = 0; k < 120; k++);
}
}。

相关文档
最新文档