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

网站备案没座机做网站一般几个步骤

网站备案没座机,做网站一般几个步骤,中国企业500强2023,东莞公司seo优化一、单片机做项目常识 1.行业常识 2.方案选型 3.此项目定位和思路 二、单片机的小项目介绍 1.项目名称#xff1a;基于51单片机的温度报警器 #xff08;1#xff09;主控#xff1a;stc51#xff1b; #xff08;2#xff09;编程语言#xff1a;C语言 #xff08;…一、单片机做项目常识 1.行业常识 2.方案选型 3.此项目定位和思路 二、单片机的小项目介绍 1.项目名称基于51单片机的温度报警器 1主控stc51 2编程语言C语言 3开发环境Keil 41602屏显示时间和温度当温度超过预定值时蜂鸣器和电机工作报警 5系统人机界面矩阵按键或者红外遥控器修改时间 2.硬件资源分配 优先满足硬件上已经接好的引脚 1602屏幕 P0P2^7  ;P2^5;P2^6 4*4按键 P2 串口 P3.0 P3.1 IR红外遥控器P3^2 传感器DS18B20  P3.7                  DS1302 P3.4 P3.6 步进电机四线双极性P1.0---P1.5 蜂鸣器 P1.7 3.项目流程 1编写移植封装测试顶层硬件模块操作库 2梳理定义应用层功能 3逐个实现各功能并联合调试测试功能是否正常 4实现测试使用并解决bug持续维护 4.一些小问题 三、构成建立及框架搭建 1.基本搭建 lst src         app高层时序【main存放】         driver 低层时序         include基本的全局变量 obj 2.端口分配检查确定 1602屏幕 P0P1^4  ;   P1.5    ;    P 1.6 4*4按键 P2 串口 P3.0 P3.1 IR红外遥控器P3^2 传感器DS18B20  P3.7                  DS1302 P3.4 P3.6 P3.5 步进电机四线双极性P1.0---P1.3 蜂鸣器 P1.6 四、第一个模块串口 1.移植并调试确认基本功能 uart.c #includeuart.h//串口初始化函数 //预设计一个串口条件8位数据位1位停止位0校验位波特率9600 //初始化的主要工作是设置相关的寄存器 //使用晶振为11.0592MHz //CPU工作在12T模式下void uart_init(){//使用8bit串行接口SCON0x50;//波特率不加倍PCON0x00;//波特率相关设置TMOD0x20;//设置T1在模式2TL1249; //设定定时初值TH1 249; //设定定时器重装值TR11;//开启T1开始工作ES1;//开启串行中断允许位EA1;//开启全部中断}//串口发送单个字符 void uart_send_byte(unsigned char a){//发送一个字节SBUFa;//查看当然串口是否在忙//根据SCON中的TI位可以判断当前串口是否在忙//如果数据8位发送结束则硬件自动将TI1则TI0表示程序还没有发送结束if(!TI)//软件复位TITI0; }void uart_send_string(unsigned char *str) {while (*str ! \0){uart_send_byte(*str); // 发送1个字符str; // 指针指向下一个字符} } 2.封装 1.何为封装 1隐藏 2保护 2.封装低层接口实践 uart.h //开头2行和最后1行加起来构成一种格式这种格式利用了c语言的预处理中的条件编译技术 //实现的效果就是防止该头文件被重复包含构成的错误 #ifndef __UART__H__ #define __UART__H__ #includereg51.h//串口初始化函数 //预设计一个串口条件8位数据位1位停止位0校验位波特率9600 //初始化的主要工作是设置相关的寄存器 //使用晶振为11.0592MHz //CPU工作在12T模式下 void uart_init();//串口发送单个字符 void uart_send_byte(unsigned char a); //串口发送字符串 void uart_send_string(unsigned char *str);//延时函数 void Delay2000ms(); //11.0592MHz#endif 五、DS18B20移植温度显示 1.static static void Delay750us()表示只能在该文件内部使用 2.高层时序 初始化函数将复位和检测是否存在分为两个函数方便封装 /******************************************************************************* * 函 数 名 : ds18b20_reset * 函数功能 : 复位DS18B20 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void ds18b20_reset(void) {DS18B20_PORT0; //拉低DQdelay_10us(75); //拉低750usDS18B20_PORT1; //DQ1delay_10us(2); //20US }/******************************************************************************* * 函 数 名 : ds18b20_check * 函数功能 : 检测DS18B20是否存在 * 输 入 : 无 * 输 出 : 1:未检测到DS18B20的存在0:存在 *******************************************************************************/ u8 ds18b20_check(void) {u8 time_temp0;while(DS18B20_PORTtime_temp20) //等待DQ为低电平{time_temp;delay_10us(1); }if(time_temp20)return 1; //如果超时则强制返回1else time_temp0;while((!DS18B20_PORT)time_temp20) //等待DQ为高电平{time_temp;delay_10us(1);}if(time_temp20)return 1; //如果超时则强制返回1return 0; }/******************************************************************************* * 函 数 名 : ds18b20_start * 函数功能 : 开始温度转换 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ //转换命令 void ds18b20_start(void) {ds18b20_reset();//复位ds18b20_check();//检查DS18B20ds18b20_write_byte(0xcc);//SKIP ROMds18b20_write_byte(0x44);//转换命令 }/******************************************************************************* * 函 数 名 : ds18b20_init * 函数功能 : 初始化DS18B20的IO口 DQ 同时检测DS的存在 * 输 入 : 无 * 输 出 : 1:不存在0:存在 *******************************************************************************/ u8 ds18b20_init(void) {ds18b20_reset();return ds18b20_check(); }/******************************************************************************* * 函 数 名 : ds18b20_read_temperture * 函数功能 : 从ds18b20得到温度值 * 输 入 : 无 * 输 出 : 温度数据 *******************************************************************************/ float ds18b20_read_temperture(void) {float temp;u8 dath0;u8 datl0;u16 value0;//开始转换:开启转换命令ds18b20_start();//将各个电线置为默认电平ds18b20_reset();//复位//判断当前程序是否在忙ds18b20_check();//发送读取温度命令ds18b20_write_byte(0xcc);//SKIP ROMds18b20_write_byte(0xbe);//读存储器datlds18b20_read_byte();//低字节dathds18b20_read_byte();//高字节value(dath8)datl;//合并为16位数据if((value0xf800)0xf800)//判断符号位负温度{value(~value)1; //数据取反再加1tempvalue*(-0.0625);//乘以精度 }else //正温度{tempvalue*0.0625; }return temp; }3.遇到的问题 问题double t24.5要用串口把24.5打印出来给串口助手去显示 串口助手显示方式有2种二进制方式和文本方式。文本方式最直观但是需要通过串口去发送的不是double不是int而是ASCII码的字符串 意思是想要看到25.4的uart_send_string(25.4); 所以我们需要一个函数能够把double类型的t给转成对应的字符串来去给串口显示 lcd1602.c // 显示类似于24.5这种的double类型的数字 void LcdShowDouble(unsigned char x, unsigned char y, double d) {// 第一步将double d转成字符串strunsigned char str[5] {0};// 第1步先由double的25.4得到uint的254unsigned int tmp (unsigned int)(d * 10); unsigned char c 0;// 第2步由/和%操作来得到2、5、4// 第3步将2、5、4对应的ASCII码放到字符串中去完成c (unsigned char)(tmp / 100);str[0] c 48;tmp tmp % 100; // 运算后tmp54c (unsigned char)(tmp / 10); // c 5str[1] c 48;str[2] .;tmp tmp % 10; // 运算后tmp4c (unsigned char)(tmp / 1); // c 4str[3] c 48;str[4] \0;// 第二步显示strLcdShowStr(x, y, str); } ds18b20 #include ds18b20.h #include intrins.h/******************************************************************************* * 函 数 名 : delay_10us * 函数功能 : 延时函数ten_us1时大约延时10us * 输 入 : ten_us * 输 出 : 无 *******************************************************************************/ void delay_10us(u16 ten_us) {while(ten_us--); }/******************************************************************************* * 函 数 名 : delay_ms * 函数功能 : ms延时函数ms1时大约延时1ms * 输 入 : msms延时时间 * 输 出 : 无 *******************************************************************************/ void delay_ms(u16 ms) {u16 i,j;for(ims;i0;i--)for(j110;j0;j--); } /******************************************************************************* * 函 数 名 : ds18b20_reset * 函数功能 : 复位DS18B20 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void ds18b20_reset(void) {DS18B20_PORT0; //拉低DQdelay_10us(75); //拉低750usDS18B20_PORT1; //DQ1delay_10us(2); //20US }/******************************************************************************* * 函 数 名 : ds18b20_check * 函数功能 : 检测DS18B20是否存在 * 输 入 : 无 * 输 出 : 1:未检测到DS18B20的存在0:存在 *******************************************************************************/ u8 ds18b20_check(void) {u8 time_temp0;while(DS18B20_PORTtime_temp20) //等待DQ为低电平{time_temp;delay_10us(1); }if(time_temp20)return 1; //如果超时则强制返回1else time_temp0;while((!DS18B20_PORT)time_temp20) //等待DQ为高电平{time_temp;delay_10us(1);}if(time_temp20)return 1; //如果超时则强制返回1return 0; } /******************************************************************************* * 函 数 名 : ds18b20_read_bit * 函数功能 : 从DS18B20读取一个位 * 输 入 : 无 * 输 出 : 1/0 *******************************************************************************/ u8 ds18b20_read_bit(void) {u8 dat0;DS18B20_PORT0;_nop_();_nop_();DS18B20_PORT1; _nop_();_nop_(); //该段时间不能过长必须在15us内读取数据if(DS18B20_PORT)dat1; //如果总线上为1则数据dat为1否则为0else dat0;delay_10us(5);return dat; } /******************************************************************************* * 函 数 名 : ds18b20_read_byte * 函数功能 : 从DS18B20读取一个字节 * 输 入 : 无 * 输 出 : 一个字节数据 *******************************************************************************/ u8 ds18b20_read_byte(void) {u8 i0;u8 dat0;u8 temp0;for(i0;i8;i)//循环8次每次读取一位且先读低位再读高位{tempds18b20_read_bit();dat(temp7)|(dat1);}return dat; }/******************************************************************************* * 函 数 名 : ds18b20_write_byte * 函数功能 : 写一个字节到DS18B20 * 输 入 : dat要写入的字节 * 输 出 : 无 *******************************************************************************/ void ds18b20_write_byte(u8 dat) {u8 i0;u8 temp0;for(i0;i8;i)//循环8次每次写一位且先写低位再写高位{tempdat0x01;//选择低位准备写入dat1;//将次高位移到低位if(temp)//此时表示读入位为“1”{DS18B20_PORT0;_nop_();_nop_();DS18B20_PORT1; delay_10us(6);}else{DS18B20_PORT0;delay_10us(6);DS18B20_PORT1;_nop_();_nop_(); } } }/******************************************************************************* * 函 数 名 : ds18b20_start * 函数功能 : 开始温度转换 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ //转换命令 void ds18b20_start(void) {ds18b20_reset();//复位ds18b20_check();//检查DS18B20ds18b20_write_byte(0xcc);//SKIP ROMds18b20_write_byte(0x44);//转换命令 }/******************************************************************************* * 函 数 名 : ds18b20_init * 函数功能 : 初始化DS18B20的IO口 DQ 同时检测DS的存在 * 输 入 : 无 * 输 出 : 1:不存在0:存在 *******************************************************************************/ u8 ds18b20_init(void) {ds18b20_reset();return ds18b20_check(); }/******************************************************************************* * 函 数 名 : ds18b20_read_temperture * 函数功能 : 从ds18b20得到温度值 * 输 入 : 无 * 输 出 : 温度数据 *******************************************************************************/ float ds18b20_read_temperture(void) {float temp;u8 dath0;u8 datl0;u16 value0;//开始转换:开启转换命令ds18b20_start();//将各个电线置为默认电平ds18b20_reset();//复位//判断当前程序是否在忙ds18b20_check();//发送读取温度命令ds18b20_write_byte(0xcc);//SKIP ROMds18b20_write_byte(0xbe);//读存储器datlds18b20_read_byte();//低字节dathds18b20_read_byte();//高字节value(dath8)datl;//合并为16位数据if((value0xf800)0xf800)//判断符号位负温度{value(~value)1; //数据取反再加1tempvalue*(-0.0625);//乘以精度 }else //正温度{tempvalue*0.0625; }return temp; }/* double Ds18b20ReadTemp(void) {unsigned int temp 0;unsigned char tmh 0, tml 0;double t 0;Ds18b20ChangTemp(); //先写入转换命令Ds18b20ReadTempCom(); //然后等待转换完后发送读取温度命令tml Ds18b20ReadByte(); //读取温度值共16位先读低字节tmh Ds18b20ReadByte(); //再读高字节 // temp tmh; // temp 8; // temp | tml;temp tml | (tmh 8);t temp * 0.0625;return t; }*/ 六、LCD1602移植 1.1602的接线 1602的引脚是事先接好的所以不能改变 1602屏幕 P0P2^7  ;P2^5;P2^6 2.lcd1602.c #include reg51.h #include lcd1602.h // 对LCD1602的底层以及高层时序做封装/************ 低层时序 ********************************/ static void Read_Busy() //忙检测函数判断bit7是0允许执行1禁止 {unsigned char sta; //LCD1602_DB 0xff;LCD1602_RS 0;LCD1602_RW 1;do{LCD1602_EN 1;sta LCD1602_DB;LCD1602_EN 0; //使能用完就拉低释放总线}while(sta 0x80); }static void Lcd1602_Write_Cmd(unsigned char cmd) //写命令 {Read_Busy();LCD1602_RS 0;LCD1602_RW 0; LCD1602_DB cmd;LCD1602_EN 1;LCD1602_EN 0; }static void Lcd1602_Write_Data(unsigned char dat) //写数据 {Read_Busy();LCD1602_RS 1;LCD1602_RW 0;LCD1602_DB dat;LCD1602_EN 1;LCD1602_EN 0; }/************* 高层时序 ******************************/ // 本函数用来设置当前光标位置其实就是设置当前正在编辑的位置 // 其实就是内部的数据地址指针其实就是RAM显存的偏移量 // x范围是0-15y0表示上面一行y1表示下面一行 static void LcdSetCursor(unsigned char x,unsigned char y) //坐标显示 {unsigned char addr;if(y 0)addr 0x00 x;elseaddr 0x40 x;Lcd1602_Write_Cmd(addr|0x80); }// 函数功能是从坐标(x,y)开始显示字符串str // 注意这个函数不能跨行显示因为显存地址是不连续的 // 其实我们可以封装出一个能够折行显示的函数的 void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str) //显示字符串 {LcdSetCursor(x,y); //当前字符的坐标while(*str ! \0){Lcd1602_Write_Data(*str);} }// 初始化LCD使之能够开始正常工作 void InitLcd1602() //1602初始化 {Lcd1602_Write_Cmd(0x38); //打开5*8,8位数据//Lcd1602_Write_Cmd(0x0c); // 打开显示并且无光标Lcd1602_Write_Cmd(0x0f); // 打开显示并且光标闪烁Lcd1602_Write_Cmd(0x06);Lcd1602_Write_Cmd(0x01); //清屏 } 3.lcd1602.h #ifndef __lcd1602__H__ #define __lcd1602__H__#includereg51.h// IO接口定义 #define LCD1602_DB P0 //data bus 数据总线 // 控制总线 sbit LCD1602_RS P2^6; //选择读取数据/命令 sbit LCD1602_RW P2^5; //选择读/写 sbit LCD1602_EN P2^7; //使能#define u8 unsigned char //只需要声明高层时序即可而底层时序是不需要声明 //因为我们在头文件中声明这个函数目的是为了让别的文件去包含这个 //从而调用这个头文件中声明的函数所以我们只需要声明1602.c中将来 //会被外部.c文件调用的哪些函数即可而且1602.c中自己使用的内部函数将来也 //不会被外部.c文件调用因此就不用声明了。/************* 高层时序 ******************************/ // 本函数用来设置当前光标位置其实就是设置当前正在编辑的位置 // 其实就是内部的数据地址指针其实就是RAM显存的偏移量 // x范围是0-15y0表示上面一行y1表示下面一行 void LcdSetCursor(unsigned char x,unsigned char y);// 函数功能是从坐标(x,y)开始显示字符串str // 注意这个函数不能跨行显示因为显存地址是不连续的 // 其实我们可以封装出一个能够折行显示的函数的 void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str); //void lcd1602_show_string(u8 x,u8 y,u8 *str); // 初始化LCD使之能够开始正常工作 void InitLcd1602();#endif 4.lcd与测温联调 1.将double转换为字符串 因为LCD中的显示函数要求输入的是字符串 此处我们为了设置方便要求温度只能精确到小数点后一位。 将数值转换为字符串的实质其实就是将单独一个数值强制类型转化为unsigned char //显示类似于24.5这种的double类型的数字 /**思路1先将其一位一位显示出来2然后将其强制类型转换为unsigned char3记得最后有一个\0 */ void LcdShowDouble(unsigned char x,unsigned char y,double d){// 第一步将double d转成字符串strunsigned char str[5] {0};// 第1步先由double的25.4得到uint的254unsigned int tmp (unsigned int)(d * 10); unsigned char c 0;// 第2步由/和%操作来得到2、5、4// 第3步将2、5、4对应的ASCII码放到字符串中去完成c (unsigned char)(tmp / 100);str[0] c 48;tmp tmp % 100; // 运算后tmp54c (unsigned char)(tmp / 10); // c 5str[1] c 48;str[2] .;tmp tmp % 10; // 运算后tmp4c (unsigned char)(tmp / 1); // c 4str[3] c 48;str[4] \0;// 第二步显示strLcdShowStr(x, y, str); } void main(void){double t35.4;InitLcd1602();//LcdShowStr(0,0,nihaoliaoxiaoyi);LcdShowDouble(0,0,t); } 2.输出摄氏度符号 3.注意点 我们在定义摄氏度符号的时候发现在最后的位置出现奇怪的符号是因为我们没有手动的添加结束符【‘\0’】 5.完整代码 lcd1602.c #includelcd1602.h /**显示屏显示温度和时间 */void Delay2000ms() //11.0592MHz {unsigned char i, j, k;_nop_();_nop_();i 85;j 12;k 155;do{do{while (--k);} while (--j);} while (--i); }/************ 低层时序 ********************************/ void Read_Busy() //忙检测函数判断bit7是0允许执行1禁止 {unsigned char sta; //LCD1602_DB 0xff;LCD1602_RS 0;LCD1602_RW 1;do{LCD1602_EN 1;sta LCD1602_DB;LCD1602_EN 0; //使能用完就拉低释放总线}while(sta 0x80); }void Lcd1602_Write_Cmd(unsigned char cmd) //写命令 {Read_Busy();LCD1602_RS 0;LCD1602_RW 0; LCD1602_DB cmd;LCD1602_EN 1;LCD1602_EN 0; }void Lcd1602_Write_Data(unsigned char dat) //写数据 {Read_Busy();LCD1602_RS 1;LCD1602_RW 0;LCD1602_DB dat;LCD1602_EN 1;LCD1602_EN 0; }/************* 高层时序 ******************************/ // 本函数用来设置当前光标位置其实就是设置当前正在编辑的位置 // 其实就是内部的数据地址指针其实就是RAM显存的偏移量 // x范围是0-15y0表示上面一行y1表示下面一行 void LcdSetCursor(unsigned char x,unsigned char y) //坐标显示 {unsigned char addr;if(y 0)addr 0x00 x;elseaddr 0x40 x;Lcd1602_Write_Cmd(addr|0x80); }// 函数功能是从坐标(x,y)开始显示字符串str // 注意这个函数不能跨行显示因为显存地址是不连续的 // 其实我们可以封装出一个能够折行显示的函数的 void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str) //显示字符串 {LcdSetCursor(x,y); //当前字符的坐标while(*str ! \0){Lcd1602_Write_Data(*str);}}// 初始化LCD使之能够开始正常工作 void InitLcd1602() //1602初始化 {Lcd1602_Write_Cmd(0x38); //打开5*8,8位数据Lcd1602_Write_Cmd(0x0c); // 打开显示并且无光标//Lcd1602_Write_Cmd(0x0f); // 打开显示并且光标闪烁Lcd1602_Write_Cmd(0x06);Lcd1602_Write_Cmd(0x01); //清屏 }/** 为了显示ds18b20中获取到的浮点数温度 使其可以在显示屏上显示 */ // 显示类似于24.5这种的double类型的数字 void LcdShowFloat(unsigned char x, unsigned char y, float d) {// 第一步将double d转成字符串strunsigned char str[5] {0};// 第1步先由double的25.4得到uint的254unsigned int tmp (unsigned int)(d * 10); unsigned char c 0;// 第2步由/和%操作来得到2、5、4// 第3步将2、5、4对应的ASCII码放到字符串中去完成c (unsigned char)(tmp / 100);str[0] c 48;tmp tmp % 100; // 运算后tmp54c (unsigned char)(tmp / 10); // c 5str[1] c 48;str[2] .;tmp tmp % 10; // 运算后tmp4c (unsigned char)(tmp / 1); // c 4str[3] c 48;str[4] \0;// 第二步显示strLcdShowStr(x, y, str);} 七、DS1302的移植和联调实时时钟 1.原理图和接线 DS1302 P3.4 P3.6 2.时间的封装使用结构体 1一个时间年 月 日 分 秒 周几相比于温度是一个简单变量 2C语言提供结构体这种技巧来处理复杂变量 3区分2个概念结构体类型【不占内存】和结构体变量【占内存】 4结构体这种语法使用时有套路         第一步先定义结构体类型         第二步用类型去生产结构体变量         第三步使用结构体变量其实就是使用结构体变量肚子里包着的内容 3.使用结构体读取时间前的准备工作 1.结构体的定义 //封装出来的一个表示时间的结构体类型 //类型不占内存也不表示一个具体时间但是类型可以用来生成时间 //每一个时间变量占一定的内存每一个时间变量就代表一个具体的时间 struct time_t {unsigned int year;//2023unsigned char mon;//1-12unsigned char date;//1-31【几号】unsigned char hour;//0-23unsigned char min;//0-59unsigned char sec;//0-59unsigned char day;//0-6【星期几】 }; 2.宏定义 之前我们使用DS1302的时候是使用数组来记录寄存器地址。此处我们使用结构体则使用宏定义来实现使得CPU运行时间得到提升 // 用来存储读取的时间的格式是秒分时日月周年 //unsigned char code READ_RTC_ADDR[7] {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; //unsigned char code WRITE_RTC_ADDR[7] {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c}; //用宏定义的方式来定义时间的寄存器地址 // 用宏定义的方式来定义时间的寄存器地址 格式是秒分时日月周年 //写地址 #define REG_ADDR_YEAR_WRITE 0x8c #define REG_ADDR_MON_WRITE 0x88 #define REG_ADDR_DATE_WRITE 0x86 #define REG_ADDR_HOUR_WRITE 0x84 #define REG_ADDR_MIN_WRITE 0x82 #define REG_ADDR_SEC_WRITE 0x80 #define REG_ADDR_DAY_WRITE 0x8a//读地址 #define REG_ADDR_YEAR_READ (REG_ADDR_YEAR_WRITE1) #define REG_ADDR_MON_READ (REG_ADDR_MON_WRITE1) #define REG_ADDR_DATE_READ (REG_ADDR_DATE_WRITE1) #define REG_ADDR_HOUR_READ (REG_ADDR_HOUR_WRITE1) #define REG_ADDR_MIN_READ (REG_ADDR_MIN_WRITE1) #define REG_ADDR_SEC_READ (REG_ADDR_SEC_WRITE1) #define REG_ADDR_DAY_READ (REG_ADDR_DAY_WRITE1) 3.读取函数 // 从ds1302的内部寄存器addr读出一个值作为返回值 static unsigned char ds1302_read_reg(unsigned char addr) {unsigned char i 0;unsigned char dat 0; // 用来存储读取到的一字节数据的unsigned char tmp 0;// 第1部分: 时序起始SCLK 0;delay();RST 0;delay();RST 1; // SCLK为低时RST由低变高意味着一个大的周期的开始delay();// 第2部分: 写入要读取的寄存器地址addrfor (i0; i8; i){dat addr 0x01; // SPI是从低位开始传输的DSIO dat; // 把要发送的bit数据丢到IO引脚上去准备好SCLK 1; // 制造上升沿让DS1302把IO上的值读走delay(); // 读走之后一个小周期就完了SCLK 0; // 把SCLK拉低是为了给下一个小周期做准备delay();addr 1; // 把addr右移一位}// 第3部分: 读出一字节DS1302返回给我们的值dat 0;for (i0; i8; i){// 在前面向ds1302写入addr的最后一个bit后ds1302就会将读取到的寄存器值// 的第一个bit放入到IO引脚上所以我们应该先读取IO再制造下降沿然后继续// 读取下一个bittmp DSIO;dat | (tmp i); // 读出来的数值是低位在前的SCLK 1; // 由于上面SCLK是低所以要先拉到高delay();SCLK 0; // 拉低SCLK制造一个下降沿delay();}// 第4部分: 时序结束SCLK 0; // SCLK拉低为了后面的周期时初始状态是对的delay();RST 0; // RST拉低意味着一个大周期的结束delay();// 第5部分解决读取时间是ff的问题DSIO 0;return dat; }// 用结构体方式来实现的读取时间的函数 // READ_RTC_ADDR格式是秒分时日月周年 void ds1302_read_time_struct(void) {mytime.year ds1302_read_reg(REG_ADDR_YEAR_READ) 2000;mytime.mon ds1302_read_reg(REG_ADDR_MON_READ);mytime.date ds1302_read_reg(REG_ADDR_DATE_READ);mytime.hour ds1302_read_reg(REG_ADDR_HOUR_READ);mytime.min ds1302_read_reg(REG_ADDR_MIN_READ);mytime.sec ds1302_read_reg(REG_ADDR_SEC_READ);mytime.day ds1302_read_reg(REG_ADDR_DAY_READ); } 4.日期转换为字符串 因为我们获取到的数值是一串字符串而我们要的是4位的年2位的日期 所以我们为了把它区分开来同时将其转换为字符串输出到lcd1602上 lcd1602.c 我们封装了2个函数分别将数值转换为字符串 // 实现一个子函数将十进制的4位整数转成一个字符串 void Int2Str4(unsigned int dat, unsigned char str[], unsigned char index) {unsigned char c 0;// 假设dat2017c dat / 1000; // c 2str[index0] c 0; // 第1位入库dat % 1000; // dat 017c dat / 100; // c 0str[index1] c 0; // 第2位入库dat % 100; // dat 17c dat / 10; // c 1str[index2] c 0; // 第3位入库dat % 10; // dat 7c dat / 1; // c 7str[index3] c 0; // 第4位入库 }// 实现一个子函数将十进制的2位整数转成一个字符串 void Int2Str2(unsigned int dat, unsigned char str[], unsigned char index) {unsigned char c 0;// 假设dat17c dat / 10; // c 1str[index0] c 0; // 第1位入库dat % 10; // dat 7c dat / 1; // c 7str[index1] c 0; // 第2位入库 }// LCD1602上显示time_t void LcdShowTimeT(unsigned char x, unsigned char y, struct time_t ti) {// 第一步将struct time_t ti转成字符串str// 格式20170406113515-4unsigned char str[17] {0};// 格式化time_t里面的各个时间然后填充str// 年的格式化str[0]-str[3]放年字符串Int2Str4(ti.year, str, 0);// 月的格式化 ,str[4]-str[5]Int2Str2(ti.mon, str, 4);// 日的格式化 ,str[6]-str[7]Int2Str2(ti.date, str, 6);// 时的格式化 ,str[8]-str[9]Int2Str2(ti.hour, str, 8);// 分的格式化 ,str[10]-str[11]Int2Str2(ti.min, str, 10);// 秒的格式化 ,str[12]-str[13]Int2Str2(ti.sec, str, 12);// 填充了一个- str[14]str[14] -;// 周几的格式化 ,str[15]str[15] ti.day 0;str[16] \0;// 第二步显示strLcdShowStr(x, y, str); } main.c unsigned char c0;InitLcd1602();LcdShowStr(0,0,temp);//0-4//显示°CLcdShowStr(9,0,du);while(1){//读取温度并显示tDs18b20ReadTemp2();//显示温度值LcdShowDouble(5,0,t);//读取时间并且显示ds1302_read_time_struct();LcdShowTimeT(0,1,mytime);} 5.进制转换 【单片机】13-实时时钟DS1302-CSDN博客 BCD码与十进制数间转换_bcd码转十进制-CSDN博客 BCD码看起来像十进制但是实际上是十六进制 我们想要机器可以识别十六进制则应该将其外观修改为真正的十六进制【也就是把外观和本质都修改为十六进制】bcd---》hex 比如我们通过ds1302获得原始数据就为BCD码【此时0x24实际上是十进制所以我们要将其转换为0x18这个才是真正的十六进制】 我们在学习ds1302的时候说到读出的其实是BCD码所以才会产生乱码。故我们要进行转换才可以正确的显示。 // 实现2个子函数分别实现从bcd码转十六进制和十六进制转bcd码 unsigned char bcd2hex(unsigned char bcd) {// 譬如我们现在要把bcd码0x24转成240x18// 思路就是分2步// 第1步先从0x24得到2和4// ((bcd 0xf0) 4) 高4位也就是2// (bcd 0x0f) 低4位也就是4// 第2步由2*104得到24return (((bcd 0xf0) 4) * 10 (bcd 0x0f)); }unsigned char hex2bcd(unsigned char hex) {// 就是要把24转成0x24// 第一步先由24得到2和4// (24 / 10) 就是2 (24 % 10)就是4// 第二步再组合成0x24return (((hex / 10) 4) | (hex % 10)); }// 用结构体方式来实现的读取时间的函数 // READ_RTC_ADDR格式是秒分时日月周年 void ds1302_read_time_struct(void) {mytime.year bcd2hex(ds1302_read_reg(REG_ADDR_YEAR_READ)) 2000;mytime.mon bcd2hex(ds1302_read_reg(REG_ADDR_MON_READ));mytime.date bcd2hex(ds1302_read_reg(REG_ADDR_DATE_READ));mytime.hour bcd2hex(ds1302_read_reg(REG_ADDR_HOUR_READ));mytime.min bcd2hex(ds1302_read_reg(REG_ADDR_MIN_READ));mytime.sec bcd2hex(ds1302_read_reg(REG_ADDR_SEC_READ));mytime.day bcd2hex(ds1302_read_reg(REG_ADDR_DAY_READ)); }6.时间设置 我们要向DS1302中写入时间让其按照这个时间接着往下走 因为我们传入的时间是十进制要被DS1302所识别着应该转换为BCD码才可以所以使用hex2bcd。【因为BCD码只能识别0-256所以我们需要在“年”后面-2000】 ds1302.c // 向ds1302的内部寄存器addr写入一个值value static void ds1302_write_reg(unsigned char addr, unsigned char value) {unsigned char i 0;unsigned char dat 0;// 第1部分: 时序起始SCLK 0;delay();RST 0;delay();RST 1; // SCLK为低时RST由低变高意味着一个大的周期的开始delay();// 第2部分: 写入第1字节addrfor (i0; i8; i){dat addr 0x01; // SPI是从低位开始传输的DSIO dat; // 把要发送的bit数据丢到IO引脚上去准备好SCLK 1; // 制造上升沿让DS1302把IO上的值读走delay(); // 读走之后一个小周期就完了SCLK 0; // 把SCLK拉低是为了给下一个小周期做准备delay();addr 1; // 把addr右移一位}// 第3部分: 写入第2字节valuefor (i0; i8; i){dat value 0x01; // SPI是从低位开始传输的DSIO dat; // 把要发送的bit数据丢到IO引脚上去准备好SCLK 1; // 制造上升沿让DS1302把IO上的值读走delay(); // 读走之后一个小周期就完了SCLK 0; // 把SCLK拉低是为了给下一个小周期做准备delay();value value 1; // 把addr右移一位}// 第4部分: 时序结束SCLK 0; // SCLK拉低为了后面的周期时初始状态是对的delay();RST 0; // RST拉低意味着一个大周期的结束delay(); }//用结构体方式在实现时间的修改函数 //本函数用于向DS1302中写入一个时间t1 void ds1302_write_time_struct(struct time_t t1){ds1302_write_reg(0x8E, 0x00); // 去掉写保护// 依次写各个时间寄存器ds1302_write_reg(REG_ADDR_YEAR_WRITE, (hex2bcd(t1.year - 2000)));ds1302_write_reg(REG_ADDR_MON_WRITE, (hex2bcd(t1.mon)));ds1302_write_reg(REG_ADDR_DATE_WRITE, (hex2bcd(t1.date)));ds1302_write_reg(REG_ADDR_HOUR_WRITE, (hex2bcd(t1.hour)));ds1302_write_reg(REG_ADDR_MIN_WRITE, (hex2bcd(t1.min)));ds1302_write_reg(REG_ADDR_SEC_WRITE, (hex2bcd(t1.sec)));ds1302_write_reg(REG_ADDR_DAY_WRITE, (hex2bcd(t1.day)));ds1302_write_reg(0x8E, 0x80); // 打开写保护} main.c struct time_t t1;float t;InitLcd1602();LcdShowStr(0,0,temp);LcdShowStr(9,0,du);t1.year 2023;t1.mon 10;t1.date 14;t1.hour 21;t1.min 6;t1.sec 45;t1.day 6;//将时间写入寄存器ds1302_write_time_struct(t1);while(1){//显示温度tds18b20_read_temperture();LcdShowFloat(5,0,t);// 读取时间并显示ds1302_read_time_struct();LcdShowTimeT(0, 1, mytime);} 7.单独修改时间 //只修改年份 void ds1302_write_time_year(unsigned int year){ds1302_write_reg(0x8E, 0x00); // 去掉写保护// 依次写各个时间寄存器ds1302_write_reg(REG_ADDR_YEAR_WRITE, (hex2bcd(year - 2000)));ds1302_write_reg(0x8E, 0x80); // 打开写保护}//只修改月份 void ds1302_write_time_month(unsigned char month){ds1302_write_reg(0x8E, 0x00); // 去掉写保护// 依次写各个时间寄存器ds1302_write_reg(REG_ADDR_MON_WRITE, (hex2bcd(month - 2000)));ds1302_write_reg(0x8E, 0x80); // 打开写保护}//只修改日 void ds1302_write_time_date(unsigned char date){ds1302_write_reg(0x8E, 0x00); // 去掉写保护// 依次写各个时间寄存器ds1302_write_reg(REG_ADDR_DATE_WRITE, (hex2bcd(date - 2000)));ds1302_write_reg(0x8E, 0x80); // 打开写保护}//只修改时 void ds1302_write_time_hour(unsigned char hour){ds1302_write_reg(0x8E, 0x00); // 去掉写保护// 依次写各个时间寄存器ds1302_write_reg(REG_ADDR_HOUR_WRITE, (hex2bcd(hour - 2000)));ds1302_write_reg(0x8E, 0x80); // 打开写保护}//只修改分 void ds1302_write_time_min(unsigned char min){ds1302_write_reg(0x8E, 0x00); // 去掉写保护// 依次写各个时间寄存器ds1302_write_reg(REG_ADDR_MIN_WRITE, (hex2bcd(min - 2000)));ds1302_write_reg(0x8E, 0x80); // 打开写保护}//只修改秒 void ds1302_write_time_sec(unsigned char sec){ds1302_write_reg(0x8E, 0x00); // 去掉写保护// 依次写各个时间寄存器ds1302_write_reg(REG_ADDR_SEC_WRITE, (hex2bcd(sec - 2000)));ds1302_write_reg(0x8E, 0x80); // 打开写保护 9.注意点 1从DS1302中获取到的数据是unsigned char 所以不能超过255但是我们年份是四位数所以我们在读取时应该直接在后面加上2000 2我们从DS1302中获取到数据是BCD码所以我们需要将其转换为十六进制 3我们在显示屏上显示数据因为我们获取到的是数值但是要转换为字符串才可以进行展示所以我们要将获取到的时间转换为字符串 // LCD1602上显示time_t void LcdShowTimeT(unsigned char x, unsigned char y, struct time_t ti) {// 第一步将struct time_t ti转成字符串str// 格式20170406113515-4unsigned char str[17] {0};// 格式化time_t里面的各个时间然后填充str// 年的格式化str[0]-str[3]放年字符串Int2Str4(ti.year, str, 0);// 月的格式化 ,str[4]-str[5]Int2Str2(ti.mon, str, 4);// 日的格式化 ,str[6]-str[7]Int2Str2(ti.date, str, 6);// 时的格式化 ,str[8]-str[9]Int2Str2(ti.hour, str, 8);// 分的格式化 ,str[10]-str[11]Int2Str2(ti.min, str, 10);// 秒的格式化 ,str[12]-str[13]Int2Str2(ti.sec, str, 12);// 填充了一个- str[14]str[14] -;// 周几的格式化 ,str[15]str[15] ti.day 0;str[16] \0;// 第二步显示strLcdShowStr(x, y, str); } 4因为年份和其他时间单位的位数不同所以我们需要将其分开写成2个函数 // 实现一个子函数将十进制的4位整数转成一个字符串 void Int2Str4(unsigned int dat, unsigned char str[], unsigned char index) {unsigned char c 0;// 假设dat2017c dat / 1000; // c 2str[index0] c 0; // 第1位入库dat % 1000; // dat 017c dat / 100; // c 0str[index1] c 0; // 第2位入库dat % 100; // dat 17c dat / 10; // c 1str[index2] c 0; // 第3位入库dat % 10; // dat 7c dat / 1; // c 7str[index3] c 0; // 第4位入库 }// 实现一个子函数将十进制的2位整数转成一个字符串 void Int2Str2(unsigned int dat, unsigned char str[], unsigned char index) {unsigned char c 0;// 假设dat17c dat / 10; // c 1str[index0] c 0; // 第1位入库dat % 10; // dat 7c dat / 1; // c 7str[index1] c 0; // 第2位入库 } 5写入时间因为我们传入的是十六进制但是为了让DS1302识别所以需要将其转换为bcd码 //十六进制转换为bcd码 unsigned char hex2bcd(unsigned char hex) {// 就是要把24转成0x24// 第一步先由24得到2和4// (24 / 10) 就是2 (24 % 10)就是4// 第二步再组合成0x24return (((hex / 10) 4) | (hex % 10)); } 6写入时间函数 //用结构体方式在实现时间的修改函数 //本函数用于向DS1302中写入一个时间t1 void ds1302_write_time_struct(struct time_t t1){ds1302_write_reg(0x8E, 0x00); // 去掉写保护// 依次写各个时间寄存器ds1302_write_reg(REG_ADDR_YEAR_WRITE, (hex2bcd(t1.year - 2000)));ds1302_write_reg(REG_ADDR_MON_WRITE, (hex2bcd(t1.mon)));ds1302_write_reg(REG_ADDR_DATE_WRITE, (hex2bcd(t1.date)));ds1302_write_reg(REG_ADDR_HOUR_WRITE, (hex2bcd(t1.hour)));ds1302_write_reg(REG_ADDR_MIN_WRITE, (hex2bcd(t1.min)));ds1302_write_reg(REG_ADDR_SEC_WRITE, (hex2bcd(t1.sec)));ds1302_write_reg(REG_ADDR_DAY_WRITE, (hex2bcd(t1.day)));ds1302_write_reg(0x8E, 0x80); // 打开写保护} 八、蜂鸣器 1.接线和原理图 P1^7 2.函数封装 1.初始化 void buzzer_init(){TMOD 0x01; // T0使用16bit定时器//决定中断的时间TL0 N % 256;TH0 N / 256;TR0 1; // T0打开开始计数ET0 1; // T0中断允许EA 1; // 总中断允许BUZZER 1;// 设置响和不响的周期时间/**我们初始化频率为4KHZ则应该是1/4000HZ的周期1s1000ms1000 000us所以1/40001000 000/40001000/4256us*/count TIMELEN; //600*256usflag 0; } 2.中断函数 //timer0的isr在这里对引脚进行电平反反转以让蜂鸣器响 void timer0_isr(void) interrupt 1 using 1 {TL0 N % 256;TH0 N / 256;if (count-- 0){// 说明到了翻转的时候了// count 600;if (flag 0){// 之前是处于有声音的说明本次是从有声音到无声音的翻转flag 1;//*10:表示不响的时间是响的时间的10倍count TIMELEN*10; //这里的count数量决定蜂鸣器【不响】的时间长短}else{// 之前是处于没声音的说明本次是从没声音到有声音的翻转flag 0;BUZZER !BUZZER;count TIMELEN; //这里的count数量决定蜂鸣器【响】的时间长短}}//时间未到else{// 常规情况也就是不反转时if (flag 0){BUZZER !BUZZER; // 4999次声音}else{// 空的就可以因为不进行任何IO操作就是没声音}}} 3.提升 1.中断函数优化 //宏定义 //设置蜂鸣器的输出频率为XKHZ #define XKHZ 4 // 要定多少Khz就直接写这里 #define US (500/XKHZ) #define N (65535-US)//N(65535-(500/XKHZ))static unsigned char xKHZ0; //用于获取N的数值可以计算响或者不响 将初始化函数和中断函数中的N修改并且将count删除 //让蜂鸣器一直响的isr void timer0_isr(void) interrupt 1 using 1 {//N(65535-(500/XKHZ))TL0 (65535-(500/xKHZ)) % 256;TH0 (65535-(500/xKHZ)) / 256;// 常规情况也就是不反转时if (flag 0) //flag0表示响{BUZZER !BUZZER; // 4999次声音} } //buzzer的初始化 void buzzer_init(){TMOD 0x01; // T0使用16bit定时器//决定中断的时间 //N(65535-(500/XKHZ))TL0 (65535-(500/xKHZ)) % 256;TH0 (65535-(500/xKHZ)) / 256;TR0 1; // T0打开开始计数ET0 1; // T0中断允许EA 1; // 总中断允许BUZZER 1;flag 0; // flag 0表示有声音flag 1表示没声音xKHZ4;//默认是4khz } 2.一直响/不响 //让蜂鸣器开始响 void buzzer_start(void){flag0; }//让蜂鸣器停止响 void buzzer_stop(void){flag1; }//设置蜂鸣器响的频率 void buzzer_freq_set(unsigned char tmp){xKHZtmp;//修改蜂鸣器的频率 } 3.完整代码 #includebuzzer.h//buzzer的初始化 void buzzer_init(){xKHZ4;//默认是4khzTMOD 0x01; // T0使用16bit定时器//决定中断的时间 //N(65535-(500/XKHZ))TL0 (65535-(500/xKHZ)) % 256;TH0 (65535-(500/xKHZ)) / 256;TR0 1; // T0打开开始计数ET0 1; // T0中断允许EA 1; // 总中断允许BUZZER 1;flag 1; // flag 0表示有声音flag 1表示没声音}//让蜂鸣器一直响的isr void timer0_isr(void) interrupt 1 using 1 {//N(65535-(500/XKHZ))TL0 (65535-(500/xKHZ)) % 256;TH0 (65535-(500/xKHZ)) / 256;// 常规情况也就是不反转时if (flag 0) //flag0表示响{BUZZER !BUZZER; // 4999次声音} }//让蜂鸣器开始响 void buzzer_start(void){flag0; }//让蜂鸣器停止响 void buzzer_stop(void){flag1; }//设置蜂鸣器响的频率 void buzzer_freq_set(unsigned char tmp){xKHZtmp;//修改蜂鸣器的频率 } 4.蜂鸣器频率设置 上面的代码我们无法修改频率
http://www.hkea.cn/news/14268170/

相关文章:

  • 广州网站改版哪家好美容院顾客管理系统软件
  • 盗版小说网站建设网站服务器怎么看是哪个厂家的
  • 公司网站无法收录手表购买网站
  • 建设银行河南分行网站模板建站和定制建站
  • readme.md做网站郑州城乡建设局官网
  • 域名网站备案管理系统wordpress 未分类
  • 网站建设域名怎么选择海飞丝网站建设中面临的技术问题_并提出可行的技术解决方案
  • 重庆深蓝科技网站开发win2008r2搭建php网站
  • 旅游网站设计论文摘要企业的oa管理系统
  • 企业做网站被骗楼盘价格哪个网站做的好
  • 网站建设客户定位门户类网站如何做策划
  • 小米官方网站开发版在哪里seo小白入门教学
  • 宁德网站建设制作wordpress关注公众号可见
  • 做自媒体需要关注什么网站青海制作网站
  • 想在百度做网站自己的品牌怎么做加盟推广
  • 邯郸市教育公共服务平台贵州灵溪seo整站优化
  • 紫川网站建设请列举常见的网站推广方法
  • 领诺科技网站建设wordpress数据库迁移
  • 微信怎么建设自己网站网站效果图模板
  • 潍坊模板开发建站游戏软件开发流程
  • 零基础建设网站视频福建省住房与城乡建设厅网站
  • 2017 上海网站备案长安网站建设制作公司
  • 做网站需要的设备宁波论坛招聘
  • 沧州网站建设刘磊wordpress无法显示文章
  • 石家庄视频网站建设公司wordpress好看博客主题
  • 中小企业建站系统江西南昌网站建设哪家公司好
  • 金坛网站建设价格东莞保安公司电话
  • 《网站开发与应用福州福清网站建设
  • 做网站用vue还是用jquery网站建站费用多少
  • 建自己的网站做外贸海口商城网站建设