单片机课程设计题目:单总线和I2C总线结合实现数字温度计实验班级:设计者:指导教师:单总线和I2C总线结合实现数字温度计实验一、实验目的通过本实验,理解掌握单总线器件和I2C总线器件的应用,熟悉串行总线的操作技巧。
二、实验设备及器件IBM PC 机一台DP-51PROC 单片机综合仿真实验仪一台三、实验内容1.编写程序,通过单片机的P3.3 口控制一个DS18B20 完成数字温度的采集,然后用程序处理采集到的数据结果。
2.编写程序,通过I2C 总线器件ZLG7290 实现温度数据的输出显示。
3.结合以上两部分程序,编程实现数字式温度计的程序设计。
四、实验要求熟练掌握单总线方式器件的应用,熟悉I2C 总线协议,学习I2C 器件的使用方法。
五、实验过程和步骤(一、新建工程文件1、点击工具栏Project选项,在下拉菜单中选择New Project命令,弹出项目文件保存对话框,输入项目名后,点击保存按钮。
2、在工程建立完毕以后,uVision会弹出器件选择窗口,选择相应的器件型号。
如想修改,可点击工具栏Project选项,在下拉菜单中选择Select Device forTarget …Target‟命令。
3、点击工具栏File选项,选中New命令,新建文件,输入源程序。
4、把文件保存到磁盘中,如用汇编语言编写程序用.asm为扩展名,如用C语言编写程序用.c 为扩展名。
5、添加该文件到工程中,在Projectwindos窗口内,选中Source Group1然后点击鼠标右键,选择Add files to Group “Source Group1”,选择刚才创建的源程序文件,单击Add按钮。
(二、程序文件的编译、链接1. 安装B4 区JP12 接口上的短路帽,将B4 区的DQ 与A2 区INT1(P3.3相连。
2. 安装D5 区JP1 接口上的短路帽,将D5 区的SDA、SCL 分别与A2 区的P17、P16 相连。
3. 将D5 区的RST_L 针接上高电平。
4.按照下面的程序在Keil C51集成开发环境中建立工程文件,并进行调试仿真。
TEMPER_L EQU 36H ;存放读出温度低位数据TEMPER_H EQU 35H ;存放读出温度高位数据TEMPER_NUM EQU 37H ;存放转换后的温度值FLAG1 BIT 00HDQ BIT P3.3 ;一线总线控制端口SDA BIT P1.7 ;I2C总线定义SCL BIT P1.6MTD EQU 40H ;发送数据缓冲器MRD EQU 49H ;接收数据缓冲区;定义器件地址,变量ZLG7290 EQU 70H ;ZLG7290的器件地址ACK BIT 10H ;应答标志位SLA DA TA 50H ;器件的从地址SUBA DA TA 51H ;器件的子地址NUMBYTE DA TA 52H ;读/写的字节数变量ORG 0000HLJMP MAINORG 0100H;-------温度计主程序如下:MAIN:MOV SP,#70HDISP_LOOP:LCALL GET_TEMPER ;从DS18B20读出温度数据LCALL TEMPER_COV ;转换读出的温度数据并保存LCALL DELAYMOV MTD,#60HMOV MTD+1,TEMPER_NUM;温度值低位ANL MTD+1,#0FHMOV SLA,#ZLG7290 ;指定器件地址MOV SUBA,#07H ;指定子地址MOV NUMBYTE,#02H ;发送2字节数据LCALL IWRNBYTE ;调用写2字节数据程序MOV MTD,#61HMOV A,TEMPER_NUMSWAP AANL A,#0FHMOV MTD+1,A ;温度值高位MOV SLA,#ZLG7290 ;指定器件地址MOV SUBA,#07H ;指定子地址MOV NUMBYTE,#02H ;发送2字节数据LCALL IWRNBYTE ;调用写2字节数据程序LCALL DELAYSJMP DISP_LOOP ;温度循环采集显示;-------读出转换后的温度值GET_TEMPER:SETB DQ ; 定时入口BCD: LCALL INIT_1820JB FLAG1,S22LJMP BCD ; 若DS18B20不存在则返回S22: LCALL DELAY1 MOV A,#0CCH ; 跳过ROM匹配------0CCLCALL WRITE_1820MOV A,#44H ; 发出温度转换命令LCALL WRITE_1820NOPLCALL DELAYLCALL DELAYCBA: LCALL INIT_1820JB FLAG1,ABCLJMP CBAABC: LCALL DELAY1MOV A,#0CCH ; 跳过ROM匹配LCALL WRITE_1820MOV A,#0BEH ; 发出读温度命令LCALL WRITE_1820LCALL READ_18200 ;READ_1820RET;-------读DS18B20的程序,从DS18B20中读出一个字节的数据READ_1820: MOV R2,#8RE1: CLR CSETB DQNOPNOPCLR DQNOPNOPNOPSETB DQMOV R3,#7DJNZ R3,$MOV C,DQMOV R3,#23DJNZ R3,$RRC ADJNZ R2,RE1RET;-------写DS18B20的程序WRITE_1820:MOV R2,#8CLR CWR1820: CLR DQMOV R3,#6DJNZ R3,$RRC AMOV DQ,CMOV R3,#23DJNZ R3,$SETB DQNOPDJNZ R2,WR1820SETB DQRET;-------读DS18B20的程序,从DS18B20中读出两个字节的温度数据READ_18200:MOV R4,#2 ; 将温度高位和低位从DS18B20中读出MOV R1,#36H ; 低位存入36H(TEMPER_L,高位存入35H(TEMPER_H RE00: MOV R2,#8RE01: CLR CSETB DQNOPNOPCLR DQNOPNOPNOPSETB DQMOV R3,#7DJNZ R3,$MOV C,DQMOV R3,#23DJNZ R3,$RRC ADJNZ R2,RE01MOV @R1,ADEC R1DJNZ R4,RE00RET;-------将从DS18B20中读出的温度数据进行转换TEMPER_COV:MOV A,#0F0HANL A,TEMPER_L ; 舍去温度低位中小数点后的四位温度数值SWAP A MOV TEMPER_NUM,AMOV A,TEMPER_LJNB A CC.3,TEMPER_COV1 ; 四舍五入去温度值INC T EMPER_NUMTEMPER_COV1:MOV A,TEMPER_HANL A,#07HSWAP AADD A,TEMPER_NUMMOV TEMPER_NUM,A ; 保存变换后的温度数据LCALL BIN_BCDRET;-------将16进制的温度数据转换成压缩BCD码BIN_BCD:MOV DPTR,#TEMP_TABMOV A,TEMPER_NUMMOVC A,@A+DPTRMOV TEMPER_NUM,ARETTEMP_TAB:DB 00H,01H,02H,03H,04H,05H,06H,07H DB 08H,09H,10H,11H,12H,13H,14H,15H DB 16H,17H,18H,19H,20H,21H,22H,23H DB 24H,25H,26H,27H,28H,29H,30H,31H DB 32H,33H,34H,35H,36H,37H,38H,39H DB 40H,41H,42H,43H,44H,45H,46H,47H DB 48H,49H,50H,51H,52H,53H,54H,55H DB 56H,57H,58H,59H,60H,61H,62H,63H DB 64H,65H,66H,67H,68H,69H,70H,71H DB 72H,73H,74H,75H,76H,77H,78H,79H DB 80H,81H,82H,83H,84H,85H,86H,87H DB 88H,89H,90H,91H,92H,93H,94H,95H DB 96H,97H,98H,99H;-------DS18B20初始化程序INIT_1820:SETB DQNOPCLR DQMOV R0,#80HTSR1: DJNZ R0,TSR1 ; 延时SETB DQMOV R0,#25H ;96US-25HTSR2: DJNZ R0,TSR2JNB D Q,TSR3LJMP TSR4 ; 延时TSR3: SETB FLAG1 ; 置标志位,表示DS1820存在LJMP TSR5 TSR4: CLR FLAG1 ; 清标志位,表示DS1820不存在LJMP TSR7 TSR5: MOV R0,#06BH ;200USTSR6: DJNZ R0,TSR6 ; 延时TSR7: SETB DQRET;-------重新写DS18B20暂存存储器设定值RE_CONFIG:JB FLAG1,RE_CONFIG1 ; 若DS18B20存在,转RE_CONFIG1 RET RE_CONFIG1:MOV A,#0CCH ; 发SKIP ROM命令LCALL WRITE_1820MOV A,#4EH ; 发写暂存存储器命令LCALL WRITE_1820MOV A,#00H ; TH(报警上限中写入00H LCALL WRITE_1820MOV A,#00H ; TL(报警下限中写入00H LCALL WRITE_1820MOV A,#7FH ; 选择12位温度分辨率LCALL WRITE_1820RET;------------------延时子程序DELAY:MOV R7,#00HMIN: D JNZ R7,YS500RETYS500: LCALL YS500USLJMP MINYS500US:MOV R6,#00HDJNZ R6,$RETDELAY1: MOV R7,#20HDJNZ R7,$RET$INCLUDE(VI2C_ASM.INC ;包含VIIC软件包;END;启动I2C总线子程序START: SETB SDANOPSETB SCL ;起始条件建立时间大于4.7us NOPNOPNOPNOPNOPCLR SDANOP ;起始条件锁定时大于4usNOPNOPNOPNOPCLR SCL ;钳住总线,准备发数据NOPRET;结束总线子程序STOP: CLR SDANOPSETB SCL ;发送结束条件的时钟信号NOP ;结束总线时间大于4usNOPNOPNOPNOPSETB SDA ;结束总线NOP ;保证一个终止信号和起始信号的空闲时间大于4.7us NOPNOPNOPRET;发送应答信号子程序MACK: CLR SDA ;将SDA置0NOPNOPSETB SCLNOP ;保持数据时间,即SCL为高时间大于4.7us NOPNOPNOPNOPCLR SCLNOPNOPRET;发送非应答信号MNACK: SETB SDA ;将SDA置1NOPNOPSETB SCLNOPNOP ;保持数据时间,即SCL为高时间大于4.7us NOPNOPNOPCLR SCLNOPNOPRET;检查应答位子程序;返回值,ACK=1时表示有应答CACK: SETB SDANOPNOPSETB SCLCLR ACKNOPNOPMOV C,SDAJC CENDSETB ACK ;判断应答位CEND: NOPCLR SCLNOPRET;发送字节子程序;字节数据放入ACC;每发送一字节要调用一次CACK子程序,取应答位WRBYTE: MOV R0,#08H WLP: RLC A ;取数据位JC WR1SJMP WR0 ;判断数据位WLP1: DJNZ R0,WLPNOPRETWR1: SETB SDA ;发送1 NOPSETB SCLNOPNOPNOPNOPNOPCLR SCLSJMP WLP1WR0: CLR SDA ;发送0 NOPSETB SCLNOPNOPNOPNOPNOPCLR SCLSJMP WLP1;读取字节子程序;读出的值在ACC;每取一字节要发送一个应答/非应答信号RDBYTE: MOV R0,#08HRLP: SETB SDANOPNOPNOPNOPSETB SCL ;时钟线为高,接收数据位NOPNOPNOP ;+1NOP ;+1NOP ;+1NOP ;+1NOP ;+1MOV C,SDA ;读取数据位MOV A,R2CLR SCL ;将SCL拉低,时间大于4.7us RLC A ;进行数据位的处理MOV R2,ANOPNOPNOPNOP ;+1NOP ;+1NOP ;+1NOPNOPNOP ;+1NOPNOP ;+1NOP ;+1DJNZ R0,RLP ;未够8位,再来一次RET;=========================================================== ====================== =======;=========================================================== ====================== =======; 以下是用户接口子程序;;无子地址器件写字节数据;入口参数: 数据为ACC、器件从地址SLA;占用: A、R0、CYIWRBYTE: PUSH ACCIWBLOOP: LCALL START ;起动总线MOV A,SLALCALL WRBYTE ;发送器件从地址LCALL CACKJNB ACK,RETWRB ;无应答则跳转POP ACC ;写数据LCALL WRBYTELCALL CACKLCALL STOPRETRETWRB: POP ACCLCALL STOPRET;无子地址器件读字节数据;入口参数: 器件从地址SLA;出口参数: 数据为ACC;占用:A 、R0、R2 、CY IRDBYTE: LCALL STARTMOV A,SLA ;发送器件从地址INC ALCALL WRBYTELCALL CACKJNB ACK,RETRDBLCALL RDBYTE ;进行读字节操作LCALL MNACK ;发送非应信号RETRDB: LCALL STOP ;结束总线RET;向器件指定子地址写N字节数据;入口参数: 器件从地址SLA、器件子地址SUBA 、发送数据缓冲区MTD、发送字节数NUMBYTE; 占用: A 、R0 、R1 、R3 、CYIWRNBYTE: MOV A,NUMBYTEMOV R3,ALCALL START ;起动总线MOV A,SLALCALL WRBYTE ;发送器件从地址LCALL CACKJNB ACK,RETWRN ;无应答则退出MOV A,SUBA ;指定子地址LCALL WRBYTELCALL CACKMOV R1,#MTDWRDA: MOV A,@R1LCALL WRBYTE ;开始写入数据LCALL CACKJNB ACK,IWRNBYTEINC R1DJNZ R3,WRDA ;判断写完没有RETWRN: LCALL STOPRET;向器件指定子地址读取N字节数据;入口参数: 器件从地址SLA、器件子地址SUBA、接收字节数NUMBYTE ;出口参数: 接收数据缓冲区MTD;占用:A、R0、R1、R2、R3、CYIRDNBYTE: MOV R3,NUMBYTELCALL STARTMOV A,SLALCALL WRBYTE ;发送器件从地址LCALL CACKJNB ACK,RETRDNMOV A,SUBA ;指定子地址LCALL WRBYTELCALL CACKLCALL START ;重新起动总线MOV A,SLAINC A ;准备进行读操作LCALL WRBYTELCALL CACKJNB ACK,IRDNBYTEMOV R1,#MRDRDN1: LCALL RDBYTE ;读操作开始MOV @R1,A;NOP ;+1;NOP ;+1DJNZ R3,SACKLCALL MNACK ;最后一字节发非应答位RETRDN: LCALL STOP ;并结束总线RETSACK: LCALL MACKINC R1SJMP RDN1;无子地址器件写N字节数据;入口参数: 器件从地址SLA、发送数据缓冲区MTD、发送字节数NUMBYTE ; 占用: A 、R0 、R1 、R3 、CY;不发送子地址SUBA,直接发送多个数据.IWRNBYTEEXT:MOV A,NUMBYTEMOV R3,ALCALL START ;起动总线MOV A,SLALCALL WRBYTE ;发送器件从地址LCALL CACKJNB ACK,RETWRNE ;无应答则退出MOV R1,#MTDWRDAE: MOV A,@R1LCALL WRBYTE ;开始写入数据LCALL CACKJNB ACK,RETWRNEINC R1DJNZ R3,WRDAE ;判断写完没有RETWRNE: LCALL STOPRET;无子地址器件读取N字节数据;入口参数: 器件从地址SLA、器件子地址SUBA、接收字节数NUMBYTE;出口参数: 接收数据缓冲区MTD;占用:A、R0、R1、R2、R3、CY;说明:此函数不发送子址,也不重新启动总线,而是直接读取多个数据. IRDNBYTEEXT:MOV R3,NUMBYTELCALL STARTMOV A,SLAINC ALCALL WRBYTE ;发送器件从地址LCALL CACKJNB ACK,RETRDNEMOV R1,#MRDRDNE1: LCALL RDBYTE ;读操作开始MOV @R1,ADJNZ R3,SACKELCALL MNACK ;最后一字节发非应答位RETRDNE: LCALL STOP ;并结束总线RETSACKE: LCALL MACKINC R1SJMP RDNE1软件调试的具体步骤如下:1打开keil集成开发环境,新建一个新的工程文件。