当前位置: 首页 > news >正文

串口通信02 温度传感DS18B20 01 day49

九:串口通信

通信:无线和有线

​ 单工 半双工 全双工

并行:多个数据线 串行:一根数据线

同步:通信双方使用同一个时钟,SPI信息帧,有CLK引脚

异步:通信双方使用不同时钟,双方要固定的数据帧(0起始,1停止)和传输速度(波特率,一般都是9600bps = 1s:单位时间传输了多少个码元,这里用二进制码元),无CLK引脚

空闲时总线保持高电平。起始信号:由高到低 起始信号:由低到高

数据位:5,6,7,8位 需要起始位:1~2位

校验位:奇,偶,无 //一般自定义校验规则

停止信号:由低到高 停止位:1~2位

eg:11001100 实际数据:0x33,数据头是低位

一:测试发送和接受

//定时器0
#include <reg51.h>unsigned char recv = 0;
// 硬件接口定义
sbit RCLK = P3^5;
sbit SRCLK = P3^6;
sbit SER = P3^4;// 延时函数(简易版)
void delayn(unsigned char n) {while(n--);
}unsigned char code digit_table[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};// 74HC595 写入一个字节
void write_74hc595(unsigned char dat) {unsigned char i;for(i = 0; i < 8; i++) {SER = (dat & (1 << (7 - i))) ? 1 : 0;SRCLK = 0;delayn(1);SRCLK = 1;delayn(1);}RCLK = 0;delayn(1);RCLK = 1;
}// 数码管图案数据(0~9)
unsigned char code h_data[10 * 8] = {0x00, 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, 0x00, 0x01, 0x7f, 0x21, 0x00, 0x00, 0x00, 0x00,	0x00, 0x39, 0x45, 0x45, 0x45, 0x27, 0x00, 0x00,	0x00, 0x36, 0x49, 0x49, 0x49, 0x22, 0x00, 0x00,0x00, 0x04, 0x7f, 0x24, 0x14, 0x0c, 0x00, 0x00,0x00, 0x4e, 0x51, 0x51, 0x51, 0x72, 0x00, 0x00,	0x00, 0x26, 0x49, 0x49, 0x49, 0x3e, 0x00, 0x00,0x00, 0x70, 0x4f, 0x40, 0x40, 0x40, 0x00, 0x00,	0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00,0x00, 0x3e, 0x49, 0x49, 0x49, 0x32, 0x00, 0x00
};unsigned char num = 0; void dispaly_num(unsigned char num)
{unsigned char i = 0;	for(i = 0; i < 8; i++){write_74hc595(1 << (7 - i));P0 = ~h_data[i + num * 8];delayn(100);P0 = 0xff;}	
}#if 0
void serial_server() interrupt 4 
{if(TI)TI = 0;//清 发送中断标志if(RI)RI = 0;//清 发送中断标志recv = SBUF;//接受串口数据switch(recv){case 0:num = 0; P0 = digit_table[0];break;case 1:num = 1; P0 = digit_table[1];break;case 2:num = 2; P0 = digit_table[2];break;case 3:num = 3; P0 = digit_table[3];break;case 4:num = 4; P0 = digit_table[4];break;case 5:num = 5; P0 = digit_table[5];break;case 6:num = 6; P0 = digit_table[6];break;case 7:num = 7; P0 = digit_table[7];break;case 8:num = 8; P0 = digit_table[8];break;case 9:num = 9; P0 = digit_table[9];break;default: SBUF = 0X0E;P0 = digit_table[10];break;}}
#endifvoid uart_init(void)
{SCON = 0x50;			TMOD &= 0x0F;		TMOD |= 0x20;		TL1 = 0xFD;	TH1 = 0xFD;		ES = 1;EA = 1;ET1 = 0;		TR1 = 1;}void uart_send(unsigned char ch)
{TI = 0;SBUF = ch;while(!TI);
}unsigned char uart_recv(void)
{unsigned char ch = 0;while(!RI);ch = SBUF;RI = 0;return ch;
}// 主函数
void main(void)
{unsigned char ch = 0;uart_init();while(1){ch = uart_recv();ch += 1;uart_send(ch);}	
#if 0uart_init();while(1){dispaly_num(num);}
#endif
}
//如果不用中断的话,只有端口一直发,数码管才能呢个显示,但是是频闪状态,和中断相比,缺点很大
#include <reg51.h>unsigned char recv = 0;
// 硬件接口定义
sbit RCLK = P3^5;
sbit SRCLK = P3^6;
sbit SER = P3^4;// 延时函数(简易版)
void delayn(unsigned char n) {while(n--);
}unsigned char code digit_table[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};// 74HC595 写入一个字节
void write_74hc595(unsigned char dat) {unsigned char i;for(i = 0; i < 8; i++) {SER = (dat & (1 << (7 - i))) ? 1 : 0;SRCLK = 0;delayn(1);SRCLK = 1;delayn(1);}RCLK = 0;delayn(1);RCLK = 1;
}// 数码管图案数据(0~9)
unsigned char code h_data[10 * 8] = {0x00, 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, 0x00, 0x01, 0x7f, 0x21, 0x00, 0x00, 0x00, 0x00,	0x00, 0x39, 0x45, 0x45, 0x45, 0x27, 0x00, 0x00,	0x00, 0x36, 0x49, 0x49, 0x49, 0x22, 0x00, 0x00,0x00, 0x04, 0x7f, 0x24, 0x14, 0x0c, 0x00, 0x00,0x00, 0x4e, 0x51, 0x51, 0x51, 0x72, 0x00, 0x00,	0x00, 0x26, 0x49, 0x49, 0x49, 0x3e, 0x00, 0x00,0x00, 0x70, 0x4f, 0x40, 0x40, 0x40, 0x00, 0x00,	0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00,0x00, 0x3e, 0x49, 0x49, 0x49, 0x32, 0x00, 0x00
};unsigned char num = 0; void dispaly_num(unsigned char num)
{unsigned char i = 0;	for(i = 0; i < 8; i++){write_74hc595(1 << (7 - i));P0 = ~h_data[i + num * 8];delayn(100);P0 = 0xff;}	
}#if 0
void serial_server() interrupt 4 
{if(TI)TI = 0;//清 发送中断标志if(RI)RI = 0;//清 发送中断标志recv = SBUF;//接受串口数据switch(recv){case 0:num = 0; P0 = digit_table[0];break;case 1:num = 1; P0 = digit_table[1];break;case 2:num = 2; P0 = digit_table[2];break;case 3:num = 3; P0 = digit_table[3];break;case 4:num = 4; P0 = digit_table[4];break;case 5:num = 5; P0 = digit_table[5];break;case 6:num = 6; P0 = digit_table[6];break;case 7:num = 7; P0 = digit_table[7];break;case 8:num = 8; P0 = digit_table[8];break;case 9:num = 9; P0 = digit_table[9];break;default: SBUF = 0X0E;P0 = digit_table[10];break;}}
#endifvoid uart_init(void)
{SCON = 0x50;			TMOD &= 0x0F;		TMOD |= 0x20;		TL1 = 0xFD;	TH1 = 0xFD;		ES = 1;EA = 1;ET1 = 0;		TR1 = 1;}void uart_send(unsigned char ch)
{TI = 0;SBUF = ch;while(!TI);
}unsigned char uart_recv(void)
{unsigned char ch = 0;while(!RI);ch = SBUF;RI = 0;return ch;
}// 主函数
void main(void)
{unsigned char ch = 0;uart_init();while(1){ch = uart_recv();ch += 1;uart_send(ch);if(ch < 10){dispaly_num(ch);}}	
#if 0uart_init();while(1){dispaly_num(num);}
#endif
}

二:UART串口

STC89C51RC/RD+系列单片机内部集成有一个功能很强的全双工串行通信口,与传统8051单片机的串口完全兼容。设有2个互相独立的接收、发送缓冲器,可以同时发送和接收数据。发送缓冲器只能写入而不能读出,接收缓冲器只能读出而不能写入,,因而两个缓冲器可以共用一个地址码(99H)。两个缓冲器统称串行通信特殊功能寄存器SBUF

STC89C51RC/RD+系列单片机串行口对应的硬件部分对应的管脚是P3.0/RxD和P3.1/TxD。

#include <reg51.h>unsigned char recv = 0;unsigned char code digit_table[] = {0x06, // 10x5B, // 20x4F, // 30x66, // 40x6D, // 50x7D, // 60x07, // 70x7F, // 8
};void digit_select(unsigned char digit)
{unsigned char num = P2;num &= ~(0x7 << 2);  num |= (digit << 2);P2 = num;
}void serial_server() interrupt 4 
{if(TI)TI = 0;if(RI)RI = 0;recv = SBUF;switch(recv){case '1':digit_select(0); P0 = digit_table[0];break;case '2':digit_select(1); P0 = digit_table[1];break;case '3':digit_select(2); P0 = digit_table[2];break;case '4':digit_select(3); P0 = digit_table[3];break;case '5':digit_select(4); P0 = digit_table[4];break;case '6':digit_select(5); P0 = digit_table[5];break;case '7':digit_select(6); P0 = digit_table[6];break;case '8':digit_select(7); P0 = digit_table[7];break;default:P0 = 0xff;break;}}void main(void)
{
#if 1		SCON = 0x50;//设置串口工作方式,8位数据,可变波特率	TMOD &= 0x0F;		TMOD |= 0x20;//设置T1工作方式		TL1 = 0xFD;	TH1 = 0xFD;//设置9600波特率		ES = 1;//开 串口中断  //使能端EA = 1;//开 总中断	TR1 = 1;//启动定时器1
#endif//P0 = 0xEF;	while(1);}

三:通过串口通信修改led点阵数字

//定时器0
#include <reg51.h>unsigned char recv = 0;
// 硬件接口定义
sbit RCLK = P3^5;
sbit SRCLK = P3^6;
sbit SER = P3^4;// 延时函数(简易版)
void delayn(unsigned char n) {while(n--);
}unsigned char code digit_table[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};// 74HC595 写入一个字节
void write_74hc595(unsigned char dat) {unsigned char i;for(i = 0; i < 8; i++) {SER = (dat & (1 << (7 - i))) ? 1 : 0;SRCLK = 0;delayn(1);SRCLK = 1;delayn(1);}RCLK = 0;delayn(1);RCLK = 1;
}// 数码管图案数据(0~9)
unsigned char code h_data[10 * 8] = {0x00, 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, 0x00, 0x01, 0x7f, 0x21, 0x00, 0x00, 0x00, 0x00,	0x00, 0x39, 0x45, 0x45, 0x45, 0x27, 0x00, 0x00,	0x00, 0x36, 0x49, 0x49, 0x49, 0x22, 0x00, 0x00,0x00, 0x04, 0x7f, 0x24, 0x14, 0x0c, 0x00, 0x00,0x00, 0x4e, 0x51, 0x51, 0x51, 0x72, 0x00, 0x00,	0x00, 0x26, 0x49, 0x49, 0x49, 0x3e, 0x00, 0x00,0x00, 0x70, 0x4f, 0x40, 0x40, 0x40, 0x00, 0x00,	0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00,0x00, 0x3e, 0x49, 0x49, 0x49, 0x32, 0x00, 0x00
};unsigned char num = 0; void dispaly_num(unsigned char num)
{unsigned char i = 0;	for(i = 0; i < 8; i++){write_74hc595(1 << (7 - i));P0 = ~h_data[i + num * 8];delayn(100);P0 = 0xff;}	
}void serial_server() interrupt 4 
{if(TI)TI = 0;if(RI)RI = 0;recv = SBUF;switch(recv){case '0':num = 0; P0 = digit_table[0];break;case '1':num = 1; P0 = digit_table[1];break;case '2':num = 2; P0 = digit_table[2];break;case '3':num = 3; P0 = digit_table[3];break;case '4':num = 4; P0 = digit_table[4];break;case '5':num = 5; P0 = digit_table[5];break;case '6':num = 6; P0 = digit_table[6];break;case '7':num = 7; P0 = digit_table[7];break;case '8':num = 8; P0 = digit_table[8];break;case '9':num = 9; P0 = digit_table[9];break;}}// 主函数
void main(void)
{SCON = 0x50;			TMOD &= 0x0F;		TMOD |= 0x20;		TL1 = 0xFD;	TH1 = 0xFD;		ES = 1;EA = 1;		TR1 = 1;while(1){dispaly_num(num);}
}

四:总测试

//定时器0
#include <reg51.h>unsigned char recv = 0;
unsigned char recv_flag = 0;
// 硬件接口定义
sbit RCLK = P3^5;
sbit SRCLK = P3^6;
sbit SER = P3^4;// 延时函数(简易版)
void delayn(unsigned char n) {while(n--);
}void delay_ms(unsigned int num)
{unsigned char i,j;while(num--){i = 2;//看具体晶振大小j = 199;}do{while(--j);}while(--i);
}unsigned char code digit_table[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};// 74HC595 写入一个字节
void write_74hc595(unsigned char dat) {unsigned char i;for(i = 0; i < 8; i++) {SER = (dat & (1 << (7 - i))) ? 1 : 0;SRCLK = 0;delayn(1);SRCLK = 1;delayn(1);}RCLK = 0;delayn(1);RCLK = 1;
}// 数码管图案数据(0~9)
unsigned char code h_data[10 * 8] = {0x00, 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, 0x00, 0x01, 0x7f, 0x21, 0x00, 0x00, 0x00, 0x00,	0x00, 0x39, 0x45, 0x45, 0x45, 0x27, 0x00, 0x00,	0x00, 0x36, 0x49, 0x49, 0x49, 0x22, 0x00, 0x00,0x00, 0x04, 0x7f, 0x24, 0x14, 0x0c, 0x00, 0x00,0x00, 0x4e, 0x51, 0x51, 0x51, 0x72, 0x00, 0x00,	0x00, 0x26, 0x49, 0x49, 0x49, 0x3e, 0x00, 0x00,0x00, 0x70, 0x4f, 0x40, 0x40, 0x40, 0x00, 0x00,	0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00,0x00, 0x3e, 0x49, 0x49, 0x49, 0x32, 0x00, 0x00
};unsigned char num = 0; void dispaly_num(unsigned char num)
{unsigned char i = 0;	for(i = 0; i < 8; i++){write_74hc595(1 << (7 - i));P0 = ~h_data[i + num * 8];delayn(100);P0 = 0xff;}	
}#if 0
void serial_server() interrupt 4 
{if(TI)TI = 0;//清 发送中断标志if(RI)RI = 0;//清 发送中断标志recv = SBUF;//接受串口数据switch(recv){case 0:num = 0; P0 = digit_table[0];break;case 1:num = 1; P0 = digit_table[1];break;case 2:num = 2; P0 = digit_table[2];break;case 3:num = 3; P0 = digit_table[3];break;case 4:num = 4; P0 = digit_table[4];break;case 5:num = 5; P0 = digit_table[5];break;case 6:num = 6; P0 = digit_table[6];break;case 7:num = 7; P0 = digit_table[7];break;case 8:num = 8; P0 = digit_table[8];break;case 9:num = 9; P0 = digit_table[9];break;default: SBUF = 0X0E;P0 = digit_table[10];break;}}
#endifvoid uart_init(void)
{SCON = 0x50;			TMOD &= 0x0F;		TMOD |= 0x20;		TL1 = 0xFD;	TH1 = 0xFD;		ES = 1;	   EA = 1;ET1 = 0;		TR1 = 1;}#if 1
void uart_send(unsigned char ch)
{TI = 0;//上来就TI = 0 就是为了保险,防止第一次的值不是默认0; SBUF = ch;while(!TI);//TI = 0;//如果用flag的话,那就还需要清零,不然会一直闪 卡在while
}unsigned char uart_recv(void)
{unsigned char ch = 0;while(!RI);ch = SBUF;RI = 0;return ch;
}
#endif#if 1
void test() interrupt 4  //中断必须是空函数
{
#if 0unsigned char ch = 0;ch = uart_recv();  //函数放进中断-------阻塞//如果要自定义协议的话,可以把recv[i],当作数组还用,数据输入结束后,统一把数组纺发上去/收过来uart_send(ch);	   //uart_recv() 和 uart_send() 是阻塞函数://它们会 等待 RI/TI,但中断里 不应该阻塞if (ch >= '0' && ch <= '9')   num = ch - '0'; 
#endifunsigned char ch;  if (RI) {RI = 0;   //接收到,清零recv_flag = 1;     ch = SBUF;   SBUF = ch;    if (ch >= '0' && ch <= '9')  num = ch - '0';          }if (TI)         // 发送中断{TI = 0;     // 清除标志}#if 0switch(ch){case 0:num = 0; P0 = digit_table[0];break;case 1:num = 1; P0 = digit_table[1];break;case 2:num = 2; P0 = digit_table[2];break;case 3:num = 3; P0 = digit_table[3];break;case 4:num = 4; P0 = digit_table[4];break;case 5:num = 5; P0 = digit_table[5];break;case 6:num = 6; P0 = digit_table[6];break;case 7:num = 7; P0 = digit_table[7];break;case 8:num = 8; P0 = digit_table[8];break;case 9:num = 9; P0 = digit_table[9];break;default: SBUF = 0X0E;P0 = digit_table[10];}
#endif
}
#endif// 主函数
void main(void)
{
#if 0unsigned char ch = 0;uart_init();while(1){ch = uart_recv();//ch += 1;//delay_ms(65534);uart_send(ch);if(ch < 10){dispaly_num(ch);}}
#endif		
#if 1uart_init();while(1){if(recv_flag)  //会一直闪{recv_flag = 0;}dispaly_num(num);}
#endif
#if 0uart_init();while(1){dispaly_num(num);}
#endif
}

十:DS18B20

一:单总线时序结构

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

初始化:主机将总线拉低至少480us,然后释放总线,等待15~60us后,

存在的 从机 会拉低总线60-240us以响应 主机 ,之后 从机 将释放总线


下图为发送一位和接受一位的示意图:

前提:外接电源,且只有一个DS18B20

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

发送一位

​ 主机将总线拉低60~120us,然后释放总线,表示发送0;

​ 主机将总线拉低1~15us,然后释放总线,表示发送1。

​ 从机将在总线拉低30us后(典型值)(30us相当于:主机发送数据后,缓一会,丛机再读取)读取电平,整个时间片应大于60us

接收一位

​ 主机将总线拉低1~15us,然后释放总线(如果还是低电平,就是丛机还在拉低,如果上升高电平,说明从机没有动作),并在拉低后15us内读取总线电平(尽量贴近15us的末尾),

读取为低电平则为接收0,读取为高电平则为接收1,整个时间片应大于60us

发送一个字节

​ 连续调用8次发送一位的时序,依次发送一个字节的8位 (低位在前) 0 1 2 3 4 5 6 7

接收一个字节

​ 连续调用8次接收一位的时序,依次接收一个字节的8位 (低位在前)

二:DS18B20操作流程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

初始化:从机复位,庄机判断从机是否响应

ROM操作:ROM指令+本指令需要的读写操作

功能操作:功能指令+本指令需要的读写操作

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

三:数据帧(前提:外部供电且只有一个)

跳过ROM:因为只有一个温度传感,不需要发特定的数字来识别对应的温度传感

温度变换:初始化一跳过ROM→开始温度变换

温度读取:初始化→跳过ROM→[读暂存器(连续的读操作)]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

就为了读取温度数据,就读取前两位就行

四:温度存储格式

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一共16位,前8位是符号,后8位是数值大小

​ 如果是负数,那就要用补码来导出实际数值

五:ROM操作流程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

十一:AD/DA

一:基础概念

AD(Analog to Digital):模拟-数字转换,将模拟信号转换为计算机可操作的数字信号

DA(Digital to Analog):数字-模拟转换,将计算机输出的数字信号转换为模拟信号

AD/DA转换打开了计算机与模拟信号的大门,极大的提高了计算机系统的应用范围,也为模拟信号数字化处理提供了可能


模拟量:0~5v 数字量:0~255

AD转换通常有多个输入通道,用多路选择开关连接至AD转换器以实现AD多路复用的目的,提高硬件利用率

AD/DA与单片机数据传送可使用并口(速度快、原理简单),也可使用串口 (接线少、使用方便)

可将AD/DA模块直接集成在单片机内,这样直接写入/读出寄存器就可进行AD/DA转换,单片机的IO口可直接复用为AD/DA的通道

http://www.dtcms.com/a/319099.html

相关文章:

  • jetson上使用opencv的gstreamer进行MIPI和USB摄像头的连接以及udp推流
  • JAVA,Maven分模块设计
  • 语言模型(LM):n-gram模型原理与困惑度(Perplexity)计算详解
  • B-树与B+树
  • AI大模型专题:LLM大模型(初识)
  • dubbo的metadata-report是做啥的
  • 17.11 单卡24G显存微调GLM-4实战:QLoRA到全参数调优,准确率狂飙42.7%
  • Qt: WA_DontCreateNativeAncestors
  • 【缩点 拓扑序】P3119 [USACO15JAN] Grass Cownoisseur G|省选-
  • 【关于Java中==和equals( )和hashCode( )三者异同】
  • 写Rust GPU内核驱动:GPU驱动工作原理简述
  • 【性能测试】---测试工具篇
  • 医疗人效管理新标杆:盖雅工场如何赋能健康服务企业提质增效
  • 「iOS」————自动释放池底层原理
  • CSS包含块与百分比取值机制完全指南
  • 数据分析——Pandas库
  • 添加内容溢出时显示完整内容提示的功能
  • QT5.15 mingw
  • c++之 栈浅析
  • Python 数据类型及数据类型转换
  • platform总线简介和使用场景说明
  • 基于Ruby的IP池系统构建分布式爬虫架构
  • 《算法导论》第 9 章 - 中位数和顺序统计量
  • 网页图片视频一键下载+视频去重修改 ,覆盖B站等多个平台
  • 【基础知识】springboot+vue 基础框架搭建(更新中)
  • 中国MCP市场:腾讯、阿里、百度的本土化实践
  • AI绘画:生成唐初李世民全身像提示词
  • 前后端加密传数据实现方案
  • 强反光干扰下读数误差↓79%!陌讯多模态算法在仪表盘识别场景的落地优化​
  • LINUX-文件查看技巧,重定向以及内容追加,man及echo的使用