74HC573
原理
由于蓝桥杯板子上的外设很多, 所以开发板上使用了4个74HC573锁存器来复用引脚, 操控573上的外设由3个步骤组成

138译码器
将3位输入地址(A0, A1, A2)译码为8个独立的输出(D0 ~ D7)。这里我们只需要高4位也就是D4~D7的输出, 所以真值表为:
单片机P2 |
A0 |
A1 |
A2 |
D |
0x80 |
1 |
0 |
0 |
1110 1111 |
0xA0 |
1 |
0 |
1 |
1101 1111 |
0xC0 |
1 |
1 |
0 |
1011 1111 |
0xD0 |
1 |
1 |
1 |
0111 1111 |
或非门 (NOR)
因为锁存器使能(Load)为高时,Q 输出将随数据(D)输入而变。当使能为低时,将输出锁存在已建立的数据电平上。我们需要锁存器默认为锁存状态, 即被38译码器选中时才进入透明状态, 所以开发板上使用一端接地的或非门来实现对38译码器选中信号取反
NOR真值表:
A0 |
A1 |
Y |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
0 |
1 |
1 |
0 |
74HC573锁存器
锁存器使能(Load)为高时,Q 输出将随数据(D)输入而变。当使能为低时,将输出锁存在已建立的数据电平上。输出控制不影响锁存器的内部工作,即老数据可以保持.
程序设计
在将Load置高前, 改变P0为我们想要的值, 然后拉高对应Load再马上拉低Load, 这样就完成了一次数据更改与锁存操作
拉高Load时, 锁存器就已经变为透明状态了, 即输出严格等于P0, 所以可以在拉高Load之后马上拉低Load进行锁存, 但是前提是需要提前改变P0的值
1 2 3 4
| void sel_573(char num){ if(num>=4 && num<=7) P2 = (P2 & 0x1f) | (num << 5); P2 &= 0X1F; }
|
矩阵键盘
原理
程序设计
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include <STC15F2K60S2.H> #include "start.h"
unsigned char key_num(){ unsigned int temp=0; unsigned char i; unsigned int sign = 0x8000; P44=0;P42=1;P35=1;P34=1; temp = temp | (P3&0x0f);
P44=1;P42=0;P35=1;P34=1; temp = temp<<4 | (P3&0x0f);
P44=1;P42=1;P35=0;P34=1; temp = temp<<4 | (P3&0x0f); P44=1;P42=1;P35=1;P34=0; temp = temp<<4 | (P3&0x0f); for(i=0;i<16;i++) if((~temp) == (sign>>i)) return i+4; return 0; }
|
数码管
原理
程序设计
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include <STC15F2K60S2.H> #include "seg.h" #include "start.h" code unsigned char Seg_Table[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
void seg_show_char(char wei,char duan){ P0 = 0x01 << wei - 1; sel_573(6); if(duan == '.') P0 = 0x7f; else if(duan == '-') P0 = 0xBF | 0x80; else if(duan == 'P') P0 = 0x0C | 0x80; else P0 = Seg_Table[duan] | 0x80; sel_573(7); delay_ms(1); P0 = 0xff; sel_573(7); }
void seg_show_num(char wei,long int num,char len){ char i=0; int digits[8] = {0}; if (num < 0) { seg_show_char(wei++, '-'); num = -num; } while(len--) digits[i++] = num%10,num/=10; if(num<0) seg_show_char(wei++,'-'); while(i--) seg_show_char(wei++,digits[i]); }
|
DS1302
原理
程序设计
查看数据手册关于寄存器地址的定义

将表中的读写地址记为数组方便使用, 同时新建一个Timer数组来存放时间
1 2 3
| unsigned char Timer[7]={0,0,0,1,1,1,1}; unsigned char Write_DS1302_adrr[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; unsigned char Read_DS1302_adrr[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
|
定义iic端口
1 2 3
| sbit SCK=P1^7; sbit SDA=P2^3; sbit RST=P1^3;
|
写入Timer数组的时间
由于DS1302在0x8E的BIT7上有写保护, 所以在写入数据前需要给BIT7写入0关闭写保护, 之后调用官方给的Write_Ds1302_Byte()
函数对指定位置写入数据, 操作完成之后再给BIT7写入1开启写保护
1 2 3 4 5 6
| void DS1302_Config(){ char i; Write_Ds1302_Byte(0x8e, 0x00); for(i = 0; i < 7; i++) Write_Ds1302_Byte(Write_DS1302_adrr[i], Timer[i]); Write_Ds1302_Byte(0x8e, 0x80); }
|
读取时间
1 2 3 4
| void Read_DS1302_Timer(){ unsigned char i; for(i = 0; i < 7; i++) Timer[i] = Read_Ds1302_Byte(Read_DS1302_adrr[i]); }
|
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
|
#include <STC15F2K60S2.H> #include <intrins.h> #include "ds1302.h" unsigned char Timer[7]={0,0,0,1,1,1,1}; unsigned char Write_DS1302_adrr[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; unsigned char Read_DS1302_adrr[7]={0x80+1,0x82+1,0x84+1,0x86+1,0x88+1,0x8a+1,0x8c+1};
sbit SCK=P1^7; sbit SDA=P2^3; sbit RST=P1^3;
void Write_Ds1302(unsigned char temp) { unsigned char i; for (i=0;i<8;i++) { SCK = 0; SDA = temp&0x01; temp>>=1; SCK=1; } }
void Write_Ds1302_Byte( unsigned char address,unsigned char dat ) { RST=0; _nop_(); SCK=0; _nop_(); RST=1; _nop_(); Write_Ds1302(address); Write_Ds1302(dat); RST=0; }
unsigned char Read_Ds1302_Byte ( unsigned char address ) { unsigned char i,temp=0x00; RST=0; _nop_(); SCK=0; _nop_(); RST=1; _nop_(); Write_Ds1302(address); for (i=0;i<8;i++) { SCK=0; temp>>=1; if(SDA) temp|=0x80; SCK=1; } RST=0; _nop_(); SCK=0; _nop_(); SCK=1; _nop_(); SDA=0; _nop_(); SDA=1; _nop_(); return (temp); }
void DS1302_Config(){ char i; Write_Ds1302_Byte(0x8e, 0x00); for(i = 0; i < 7; i++) Write_Ds1302_Byte(Write_DS1302_adrr[i], Timer[i]); Write_Ds1302_Byte(0x8e, 0x80); }
void Read_DS1302_Timer(){ unsigned char i; for(i = 0; i < 7; i++) Timer[i] = Read_Ds1302_Byte(Read_DS1302_adrr[i]); }
|
DS18B20
原理
程序设计
DS18B20读取温度的基本流程
- DS18B20复位。
- 写入字节0xCC,跳过ROM指令。
- 写入字节0x44,开始温度转换。
- DS18B20复位。
- 写入字节0xCC,跳过ROM指令。
- 写入字节0xBE,读取高速暂存器。
- 读取暂存器的第0字节,即温度数据的LSB。
- 读取暂存器的第1字节,即温度数据的MSB。
- DS18B20复位。表示读取数据结束。
- 将LSB和MSB整合成为一个16位数据。
- 判断读取结果的符号,进行正负温度的数据处理
查阅数据手册的ROM COMMANDS
和DS18B20 FUNCTION COMMANDS
获取到所需的指令码
常用指令码:
- 0xCC: 跳过ROM指令。忽略64位ROM地址,直接向DS18B20发起各种执行指令。
- 0x44:温度转换指令。启动DS18B20进行温度转换。
- 0xBE:读取暂存器指令。DS18B20收到该指令后,会逐个输出高速暂存器中字节0到字节9的内容。如果要停止读取,必须进行复位操作。如果只需要读取温度数据,那么,在读完第0个字节和第1个字节数据后,不再理会DS18B20后面发出的数据即可。
实现读取函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| sbit DQ=P1^4; int DS18B20_Get_Tempreature(){ unsigned char LSB,MSB; int DS18B20_Tempreature; init_ds18b20(); Write_DS18B20(0xCC); Write_DS18B20(0x44); init_ds18b20(); Write_DS18B20(0xCC); Write_DS18B20(0xBE); LSB = Read_DS18B20(); MSB = Read_DS18B20(); init_ds18b20(); DS18B20_Tempreature = (MSB<<8) | LSB; if((DS18B20_Tempreature & 0xF800) == 0x000) {
DS18B20_Tempreature = (DS18B20_Tempreature >> 4) *10; DS18B20_Tempreature = DS18B20_Tempreature + (LSB & 0x0f)*0.0625*10;
} return DS18B20_Tempreature; }
|
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
#include <STC15F2K60S2.H> #include "onewire.h" sbit DQ=P1^4;
void Delay_OneWire(unsigned int t) { unsigned char i; while(t--) for(i=0;i<12;i++); }
void Write_DS18B20(unsigned char dat) { unsigned char i; for(i=0;i<8;i++) { DQ = 0; DQ = dat&0x01; Delay_OneWire(5); DQ = 1; dat >>= 1; } Delay_OneWire(5); }
unsigned char Read_DS18B20(void) { unsigned char i; unsigned char dat; for(i=0;i<8;i++) { DQ = 0; dat >>= 1; DQ = 1; if(DQ) { dat |= 0x80; } Delay_OneWire(5); } return dat; }
bit init_ds18b20(void) { bit initflag = 0; DQ = 1; Delay_OneWire(12); DQ = 0; Delay_OneWire(80); DQ = 1; Delay_OneWire(10); initflag = DQ; Delay_OneWire(5); return initflag; } int DS18B20_Get_Tempreature(){ unsigned char LSB,MSB; int DS18B20_Tempreature; init_ds18b20(); Write_DS18B20(0xCC); Write_DS18B20(0x44); init_ds18b20(); Write_DS18B20(0xCC); Write_DS18B20(0xBE); LSB = Read_DS18B20(); MSB = Read_DS18B20(); init_ds18b20();
DS18B20_Tempreature = (MSB<<8) | LSB; if((DS18B20_Tempreature & 0xF800) == 0x000) {
DS18B20_Tempreature = (DS18B20_Tempreature >> 4) *10; DS18B20_Tempreature = DS18B20_Tempreature + (LSB & 0x0f)*0.0625*10;
} return DS18B20_Tempreature; }
|
PCF8591
原理
程序设计
读取AD值
1 2 3 4 5 6 7 8 9 10 11 12
| unsigned char PCF8951_AD_Converter(unsigned char channel){ unsigned char AD=0; I2CStart(); I2CSendByte(0x90);I2CWaitAck(); I2CSendByte(0x00|channel);I2CWaitAck(); I2CStop(); I2CStart(); I2CSendByte(0X91);I2CWaitAck(); AD = I2CReceiveByte(); return AD; }
|
DA输出
1 2 3 4 5 6 7
| void PCF8951_DA_Out(unsigned char dat){ I2CStart(); I2CSendByte(0x90);I2CWaitAck(); I2CSendByte(0x40);I2CWaitAck(); I2CSendByte(dat);I2CWaitAck(); I2CStop(); }
|
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
#include "iic.h" #define DELAY_TIME 10 sbit sda=P2^1; sbit scl=P2^0;
static void I2C_Delay(unsigned char n) { do { _nop_();_nop_();_nop_();_nop_();_nop_(); _nop_();_nop_();_nop_();_nop_();_nop_(); _nop_();_nop_();_nop_();_nop_();_nop_(); } while(n--); }
void I2CStart(void) { sda = 1; scl = 1; I2C_Delay(DELAY_TIME); sda = 0; I2C_Delay(DELAY_TIME); scl = 0; }
void I2CStop(void) { sda = 0; scl = 1; I2C_Delay(DELAY_TIME); sda = 1; I2C_Delay(DELAY_TIME); }
void I2CSendByte(unsigned char byt) { unsigned char i; for(i=0; i<8; i++){ scl = 0; I2C_Delay(DELAY_TIME); if(byt & 0x80){ sda = 1; } else{ sda = 0; } I2C_Delay(DELAY_TIME); scl = 1; byt <<= 1; I2C_Delay(DELAY_TIME); } scl = 0; }
unsigned char I2CReceiveByte(void) { unsigned char da; unsigned char i; for(i=0;i<8;i++){ scl = 1; I2C_Delay(DELAY_TIME); da <<= 1; if(sda) da |= 0x01; scl = 0; I2C_Delay(DELAY_TIME); } return da; }
unsigned char I2CWaitAck(void) { unsigned char ackbit; scl = 1; I2C_Delay(DELAY_TIME); ackbit = sda; scl = 0; I2C_Delay(DELAY_TIME); return ackbit; }
void I2CSendAck(unsigned char ackbit) { scl = 0; sda = ackbit; I2C_Delay(DELAY_TIME); scl = 1; I2C_Delay(DELAY_TIME); scl = 0; sda = 1; I2C_Delay(DELAY_TIME); }
unsigned char PCF8951_AD_Converter(unsigned char channel){ unsigned char AD=0; I2CStart(); I2CSendByte(0x90);I2CWaitAck(); I2CSendByte(0x00|channel);I2CWaitAck(); I2CStop(); I2CStart(); I2CSendByte(0X91);I2CWaitAck(); AD = I2CReceiveByte(); return AD; }
void PCF8951_DA_Out(unsigned char dat){ I2CStart(); I2CSendByte(0x90);I2CWaitAck(); I2CSendByte(0x40);I2CWaitAck(); I2CSendByte(dat);I2CWaitAck(); I2CStop(); }
|