【蓝桥杯—单片机】第十一届省赛真题代码题解题笔记 | 省赛 | 真题 | 代码题 | 刷题 | 笔记
第十一届省赛真题代码部分
- 前言
- 赛题代码思路笔记
- 竞赛板配置
- 内部振荡器频率设定
- 键盘工作模式跳线
- 扩展方式跳线
- 建立模板
- 明确设计要求和初始状态
- 显示功能部分
- 数据界面
- 第一部分
- 第二部分
- 第三部分
- 调试时发现的问题
- 参数设置界面
- 第一部分
- 第二部分和第四部分
- 第三部分和第五部分
- 按键功能部分
- S4:“界面切换”按键
- 从数据界面切换到参数设置界面
- 从参数设置界面切换到数据界面
- 调试时发现的问题
- S5:“参数切换”按键
- S6:“加”按键 和 S7:"减"按键
- 调试时发现的问题
- LED指示灯功能部分
- L1、L2、L3
- L4
- DAC输出功能部分
- 最终代码
- User文件
- main.c
- Driver文件
- Init.c
- LED.c
- Seg.c
- Key.c
- onewire.c
- iic.c
- 结语
前言
本文是对蓝桥杯第十一届省赛真题的代码题做的解题笔记,只记录了代码的思路,大模板用的是B站西风老师的2024年版大模板,具体内容就不再重复记录了。
思路参考西风第十四讲内容(资料链接已经在下方给出)
https://www.bilibili.com/video/BV1TR4y1k7iz?p=23&vd_source=e2191f89c557f5ac44bb6c7aa3967c7c
关于蓝桥杯第十一届省赛真题可以在官网查看(资料链接已经在下方给出)
https://www.lanqiao.cn/courses/2786/learning/?id=100643&compatibility=false
赛题代码思路笔记
竞赛板配置
根据赛题要求完成竞赛板的配置
内部振荡器频率设定
在stc中更改输入用户程序运行时的IRC频率为12MHz
键盘工作模式跳线
配置为BTN按键模式
扩展方式跳线
配置为IO模式
建立模板
根据赛题中的硬件框图确定本赛题的框架
如图,在Driver文件夹里建立LED、数码管、按键、iic、onewire模块,在User文件夹中建立主函数模块(大模板参考西风老师的2024版大模板)。
明确设计要求和初始状态
显示功能部分
由题可知,数码管显示一共两个界面。
可以引入一个变量Seg_Disp_Mode来标记当前显示界面,因为只有两个界面,所以可以定义为bit型而不是unsigned char型以此来节省空间。
bit Seg_Disp_Mode; //数码管显示模式变量 0-数据界面 1-参数界面
再在信息处理函数的数码管部分中对当前显示模式进行判断。
判断完成后在各部分写入供该界面显示的代码。
void Seg_Proc()
{/*数码管减速*/if(Seg_Flag) return;Seg_Flag = 1;/*信息获取区域*//*数码管显示区域*/if(Seg_Disp_Mode == 0){}else{}
}
数据界面
下面来完成第一个界面的编写。
由题目可知,数据界面由三部分组成:
- 第一部分为提示符部分,是数码管的第一位,在该界面下全程显示字母C。
- 第二部分为熄灭部分,是数码管的第2到6位,在该界面下全程熄灭。
- 第三部分为实时温度显示界面,是数码管的第7到8位,在该界面下根据实时监测的温度不同显示数字实时变动。
在Driver文件夹下的Seg模块中的显示数组中加入用于表示熄灭的0xff,表示字母,表示字母C的0xc6,表示字母P的0x8c。
//code unsigned char seg_dula[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xc6,0x8c};//0-9为数字,10为熄灭,11为C,12为P
更改主模块中对应数码管控制列表中的值来控制数码管的显示情况。
第一部分
标识部分对应的数码管为第一位,更改主模块中对应数码管控制列表Seg_Buf中第一位对应的数,使其对应上Seg模块中的显示数组中的字母C。
Seg_Buf[0] = 12;//C
第二部分
熄灭部分,是数码管的第2到6位,全程为熄灭状态,在创建主函数中的Seg_Buf列表时其中的元素已经置为对应Seg模块中的显示数组中的熄灭,所以不要再做额外的更改。
第三部分
数码管显示的后两位为实时的温度数据,可以引入一个变量Temperature来存储当前获取的温度值。又由题可知,显示的温度值不含小数部分,所以可以直接用unsigned char型。
unsigned char Temperature; //实时温度变量
温度获取函数返回值为float型,将其返回值赋给unsigned char型时要先对其经行强制类型转换。
Temperature = (unsigned char)rd_temperature();
直接用整除10和取余10的形式来取出Temperature的个位和十位。
Seg_Buf[6] = Temperature / 10 ;
Seg_Buf[7] = Temperature % 10;
调试时发现的问题
在调试中发现,上电时并不是立刻显示实时温度值,而是会先显示85.00,要去掉85.00的干扰,可以在上电后先读取温度覆盖掉默认的85.00,再调用信息处理函数实现显示。
需要注意的是,单独调用温度读取函数时要再加一个750ms的延迟,因为DS18B20实现温度读取一次是750ms,如果不用延迟的话,无法实现完整的读取。
rd_temperture();
Delay750ms();
参数设置界面
由题目可知,数据界面由五部分组成:
- 第一部分为提示符部分,是数码管的第一位,在该界面下全程显示字母P。
- 第二部分为熄灭部分,是数码管的第2到3位,在该界面下全程熄灭。
- 第三部分为温度上限参数部分,是数码管的第4到5位。
- 第四部分为熄灭部分,是数码管的第6位,在该界面下全程熄灭。
- 第五部分为温度下限参数部分,是数码管的最后两位。
第一部分
标识部分对应的数码管为第一位,更改主模块中对应数码管控制列表Seg_Buf中第一位对应的数,使其对应上Seg模块中的显示数组中的字母P。
Seg_Buf[0] = 13;//C
第二部分和第四部分
不动
第三部分和第五部分
注意:题目涉及到一个可更改大小的参数时一般需要设置两个变量来标识此参数,一个用于实时的大小更改,一个用于实现控制
为什么要用两个变量,而不用一个?
答:如果只用一个变量,那么该参数在更改时同时会对它所要控制的原件产生影响,对实际的功能有干扰。
例如:当前设置值为24,需要设置的值为26,而蜂鸣器触发条件为25,则当前设置值在更改时会触发蜂鸣,但实际外部检测值并没有到要触发它的状态。
设置两个数组变量用于温度参数的显示和控制。数组的前一位为温度上限参数,后一位为温度下限参数。
unsigned char Temp_Disp[2] = {30,20};//温度变量显示数组
unsigned char Temp_Ctorl[2] = {30,20};//温度变量控制数组
对于显示只要更改数码管控制列表Seg_Buf中对应位置的值即可实现。
Seg_Buf[3] = Temp_Disp[0] / 10 % 10;
Seg_Buf[4] = Temp_Disp[0] % 10;
Seg_Buf[6] = Temp_Disp[1] / 10 % 10;
Seg_Buf[7] = Temp_Disp[1] % 10;
按键功能部分
在大模板主模块的按键处理函数中,用Key_Down判断按键按下的值。因为题目中按键涉及到4、5、6、7,所以可以添加一个switch对当前按下的按键进行一个判断。
判断完成后在各部分写入供该按键需要实现的功能的代码即可。
void Key_Proc()
{if (Key_Flag)return;Key_Flag = 1; // 设置标志位,防止重复进入Key_Val = Key_Read(); // 读取按键值Key_Down = Key_Val & (Key_Old ^ Key_Val); // 检测下降沿Key_Up = ~Key_Val & (Key_Old ^ Key_Val); // 检测上升沿Key_Old = Key_Val; // 更新按键状态switch(Key_Down){case 4:break;case 5:break;case 6:break;case 7:break;}
S4:“界面切换”按键
该按键按下后实现了界面的切换。
在显示功能部分,我们已经定义了一个变量Seg_Disp_Mode来标记当前显示的界面,当Seg_Disp_Mode为0时是数据界面,为1时是参数设置界面。
因为变量Seg_Disp_Mode是bit型数据,只在0和1之间变换,所以可以直接用异或来运算。
Seg_Disp_Mode ^= 1;
从数据界面切换到参数设置界面
当按键按下后,Seg_Disp_Mode数值变为1时,界面从数据界面切换到参数设置界面。
if(Seg_Disp_Mode == 1)//从数据界面切换到参数设置界面{}
在该界面中,刚完成切换时显示的是当前用于控制相关原件的温度参数的值,即Temp_Ctrol的值。
但是Temp_Ctrol在该界面完成温度参数的设置前一直保持不变,所以不能对Temp_Ctrol经行更改。而要对显示变量Temp_Disp进行更改,且使得刚切换时候显示的是控制值,所以要将控制值赋给显示值。
Temp_Disp[0] = Temp_Ctorl[0];
Temp_Disp[1] = Temp_Ctorl[1];
从参数设置界面切换到数据界面
当按键按下后,Seg_Disp_Mode数值变为0时,界面从参数设置界面切换到数据界面。
这里需要注意参数设置界面退出时要对设置的上下限进行合理性检查且参数设置界面在退出时设置的参数值才生效。
else//从参数界面切换到数据界面{if(Temp_Disp[0] >= Temp_Disp[1])//合理型检查{Temp_Ctorl[0] = Temp_Disp[0];Temp_Ctorl[1] = Temp_Disp[1];}}
调试时发现的问题
从参数设置界面切换回数据界面时,温度上限参数仍然处于点亮状态。
为解决此问题,可以在每次调用数据显示界面时,对Seg_Buf[3]和Seg_Buf[4]进行更改。
if(Seg_Disp_Mode == 0)//数据界面{Seg_Buf[0] = 11;//CSeg_Buf[3] = 10;Seg_Buf[4] = 10;Seg_Buf[6] = Temperature /10 % 10;Seg_Buf[7] = Temperature % 10;}
S5:“参数切换”按键
该按键是在参数设置界面下才有用的,所以,要对当前界面先进行判断,当Seg_Disp_Mode为1时,即处于参数设置界面,可以实现参数切换功能。
引入一个变量Temp_Index使其在0和1之间变换,用于对上下限的选择。
bit Temp_Index = 1;//参数数组指针
按键S5每按下一次,Temp_Index变化一次,因为Temp_Index是只在0和1之间变换的bit型数据,所以可以用异或来运算。
Temp_Index ^= 1;
S6:“加”按键 和 S7:"减"按键
加减按键在参数设置界面下才有用的,所以,还是要对当前显示的界面先进行判断。
且在该界面下,需要实现温度参数的变化,即对Temp_Disp进行更改。而加减是对上限参数的操作还是下限参数的操作在上一步中已经实现了,这里只要直接调用指向温度参数的变量Temp_Index即可。
这里还要注意的一点是温度的边界。
在减中,Temp_Disp为无符号char型,最大值为255,最小值为0,当Temp_Disp为0时再减1就会变成255,但是255超出了显示范围,且不符合当前情境下的逻辑。所以,当Temp_Disp自减1时,给它重新赋值为0,实现的是,减到0之后不会再变小。加处理与之类似,不再赘述。
case 6:if(Seg_Disp_Mode == 1){if(++Temp_Disp[Temp_Index] == 100) Temp_Disp[Temp_Index] = 99;}
break;case 7:if(Seg_Disp_Mode == 1){if(--Temp_Disp[Temp_Index] == 255) Temp_Disp[Temp_Index] = 0;}
break;
调试时发现的问题
调试时发现,无法实现上图功能。那就在数据界面切换到参数设置界面时加入对Temp_Index重置的操作。
case 4:Seg_Disp_Mode ^= 1;if(Seg_Disp_Mode == 1)//从数据界面切换到参数设置界面{Temp_Index = 1;Temp_Disp[0] = Temp_Ctorl[0];Temp_Disp[1] = Temp_Ctorl[1];}
LED指示灯功能部分
LED的部分比较简单,实现点亮只要对主模块中的Led显示数据存放数组ucLed中的数进行更改即可。
L1、L2、L3
由题目可知,实时温度和设定温度进行比较后控制对应LED的点亮与否。当条件为真时,对应LED点亮。
ucLed[0] = (Temperature > Temp_Ctorl[0]);
ucLed[1] = (Temperature <= Temp_Ctorl[0] && Temperature >= Temp_Ctorl[1]);
ucLed[2] = (Temperature < Temp_Ctorl[1]);
L4
不同于L1、L2和L3的是,L4不是在比较结果下进行操作的。
L4的点亮与否对应的是参数设置界面中的合理性检查是否通过。当合理性检查通过时,L4熄灭;反之,点亮。且需要注意的是,L4在下一次通过合理性检查前都保持点亮状态。
定义一个bit型变量,用于标记当前是否通过合理性检查。
bit Error_Flag; //错误标志位
L4的点亮状况与是否通过合理性检测有关,即与错误标志位有关。当通过合理性检查是,L4给0,熄灭;反之,给1,点亮。
ucLed[3] = Error_Flag;
回到与合理性检查相关的部分,根据上述添加对错误标志位的处理。
else//从参数界面切换到数据界面{if(Temp_Disp[0] >= Temp_Disp[1])//合理性检查{Error_Flag = 0;Temp_Ctorl[0] = Temp_Disp[0];Temp_Ctorl[1] = Temp_Disp[1];}else Error_Flag = 1;}
DAC输出功能部分
由题可知,DAC输出中的三个判断条件与L1、L2和L3正好对应。且三个条件有且仅有一个是成立的。所以可以用一个for循环来以此取出当前LED的点亮状态,当该LED点亮时,即对应的条件成立,则其他条件不成立,所以只要处理完当前条件下的DAC输出即可。
for(i=0;i<3;i++){if(ucLed[i] == 1){break;}}
调用DAC输出函数Da_Write()时需要注意的是,该函数参数为最小值为0最大值为255的unsigned char型数据。而当前题目需要的是最小为0,最大为4的DAC输出。芯片工作电压为5,可以看出成是在0-5的范围内取4、3、2三个数。
要将0-5等比例放大到0-255为51倍。
再看DAC输出值与对应条件下ucLed的关系。DAC输出4时,ucLed[0]为1;DAC输出3时,ucLed[1]为1;DAC输出2时,ucLed[2]为1。关系为4-i。
Da_Write(51*(4-i));
最终代码
User文件
main.c
/* 头文件声明区 */
#include "iic.h"
#include "onewire.h"
#include <Init.h> // 初始化底层驱动专用头文件
#include <Key.h> // 按键底层驱动专用头文件
#include <Led.h> // LED底层驱动专用头文件
#include <STC15F2K60S2.H> // 单片机寄存器专用头文件
#include <Seg.h> // 数码管底层驱动专用头文件/* 变量声明区 */
unsigned char Key_Val, Key_Down, Key_Old, Key_Up; // 按键状态变量
unsigned char Seg_Buf[8] = {10, 10, 10, 10, 10, 10, 10, 10}; // 数码管显示数据
unsigned char Seg_Point[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // 数码管小数点数据
unsigned char Seg_Pos; // 数码管扫描位置
unsigned char ucLed[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // LED显示数据
unsigned int Slow_Down; // 减速计数器
bit Seg_Flag, Key_Flag; // 数码管和按键的标志位
unsigned int Time_1s; // 1秒钟计数器
unsigned int Freq; // 频率计算变量
unsigned int Sys_Tick; // 系统时钟计数
bit Seg_Disp_Mode; //数码管显示模式变量 0-数据界面 1-参数设置界面
unsigned char Temperature; //实时温度变量
unsigned char Temp_Disp[2] = {30,20};//温度变量显示数组
unsigned char Temp_Ctorl[2] = {30,20};//温度变量控制数组
bit Temp_Index = 1;//参数数组指针
bit Error_Flag; //错误标志位/* 键盘处理函数 */
void Key_Proc()
{if (Key_Flag)return;Key_Flag = 1; // 设置标志位,防止重复进入Key_Val = Key_Read(); // 读取按键值Key_Down = Key_Val & (Key_Old ^ Key_Val); // 检测下降沿Key_Up = ~Key_Val & (Key_Old ^ Key_Val); // 检测上升沿Key_Old = Key_Val; // 更新按键状态switch(Key_Down){case 4:Seg_Disp_Mode ^= 1;if(Seg_Disp_Mode == 1)//从数据界面切换到参数设置界面{Temp_Index = 1;Temp_Disp[0] = Temp_Ctorl[0];Temp_Disp[1] = Temp_Ctorl[1];}else//从参数界面切换到数据界面{if(Temp_Disp[0] >= Temp_Disp[1])//合理型检查{Error_Flag = 0;Temp_Ctorl[0] = Temp_Disp[0];Temp_Ctorl[1] = Temp_Disp[1];}else Error_Flag = 1;}break;case 5:if(Seg_Disp_Mode == 1) Temp_Index ^= 1;break;case 6:if(Seg_Disp_Mode == 1){if(++Temp_Disp[Temp_Index] == 100) Temp_Disp[Temp_Index] = 99;}break;case 7:if(Seg_Disp_Mode == 1){if(--Temp_Disp[Temp_Index] == 255) Temp_Disp[Temp_Index] = 0;}break;}
}/* 信息处理函数 */
void Seg_Proc()
{if (Seg_Flag)return;Seg_Flag = 1; // 设置标志位Temperature = rd_temperature();if(Seg_Disp_Mode == 0)//数据界面{Seg_Buf[0] = 11;//CSeg_Buf[3] = 10;Seg_Buf[4] = 10;Seg_Buf[6] = Temperature /10 % 10;Seg_Buf[7] = Temperature % 10;}else//参数设置界面{Seg_Buf[0] = 12;//PSeg_Buf[3] = Temp_Disp[0] / 10 % 10;Seg_Buf[4] = Temp_Disp[0] % 10;Seg_Buf[6] = Temp_Disp[1] / 10 % 10;Seg_Buf[7] = Temp_Disp[1] % 10;}
}/* 其他显示函数 */
// LED显示处理函数,这里没有具体实现。
void Led_Proc()
{unsigned char i;/*Led*/ucLed[0] = (Temperature > Temp_Ctorl[0]);ucLed[1] = (Temperature <= Temp_Ctorl[0] && Temperature >= Temp_Ctorl[1]);ucLed[2] = (Temperature < Temp_Ctorl[1]);ucLed[3] = Error_Flag;/*DAC*/for(i=0;i<3;i++){if(ucLed[i] == 1){Da_Write(51*(4-i));}break;}
}/* 定时器0初始化函数 */
// 初始化定时器0,用于产生1ms的时钟中断。
void Timer0_Init(void)
{AUXR &= 0x7F; // 设置定时器时钟12T模式TMOD &= 0xF0; // 设置定时器模式为16位定时器TMOD |= 0x05;TL0 = 0; // 设置定时器初始值TH0 = 0; // 设置定时器初始值TF0 = 0; // 清除TF0标志位TR0 = 1; // 启动定时器
}/* 定时器1初始化函数 */
// 初始化定时器1,用于产生1ms的时钟中断,并允许中断。
void Timer1_Init(void)
{AUXR &= 0xBF; // 设置定时器时钟12T模式TMOD &= 0x0F; // 设置定时器模式为16位定时器TL1 = 0x18; // 设置定时器初始值TH1 = 0xFC; // 设置定时器初始值TF1 = 0; // 清除TF1标志位TR1 = 1; // 启动定时器ET1 = 1; // 使能定时器1中断EA = 1; // 开启全局中断
}/* 定时器1中断服务函数 */
// 定时器1的中断服务函数,用于更新系统时钟、处理按键和数码管显示。
void Timer1_Isr(void) interrupt 3
{/*数码管400ms的减速*/if (++Slow_Down == 400) {Seg_Flag = Slow_Down = 0; // 更新数码管显示标志位}/*按键10ms的减速*/if (Slow_Down % 10 == 0){Key_Flag = 0; // 更新按键处理标志位}/*1s的计数*/if (++Time_1s == 1000) {Time_1s = 0; // 重置1秒钟计数器Freq = TH0 << 8 | TL0; // 计算频率TH0 = 0; // 重置定时器0的值TL0 = 0;}/*信息处理*/Seg_Disp(Slow_Down % 8, Seg_Buf[Slow_Down % 8], Seg_Point[Slow_Down % 8]); // 更新数码管显示Led_Disp(Slow_Down % 8, ucLed[Slow_Down % 8]); // 更新LED显示
}void Delay750ms() //@12.000MHz
{unsigned char i, j, k;i = 35;j = 51;k = 182;do{do{while (--k);} while (--j);} while (--i);
}/* 主函数 */
// 系统初始化,设置定时器和串口,然后进入主循环。
void main()
{rd_temperature();Delay750ms();Sys_Init(); // 系统初始化Timer1_Init(); // 初始化定时器1while (1){Key_Proc(); // 处理按键Seg_Proc(); // 更新数码管显示Led_Proc(); // 更新LED显示}
}
Driver文件
Init.c
#include "init.h"void Sys_Init()
{P0 = 0xff;P2 = P2 & 0x1f | 0x80;P2 &= 0x1f;P0 = 0x00;P2 = P2 & 0x1f | 0xA0;P2 &= 0x1f;
}
LED.c
#include "LED.h"void LED_Disp(unsigned char addr,enable)
{static unsigned char temp = 0x00;static unsigned char temp_old = 0xff;if(enable) temp |= 0x01 << addr;else temp &= ~(0x01 << addr);if(temp != temp_old){P0 = ~temp;P2 = P2 & 0x1f | 0x80;P2 &= 0x1f;temp_old = temp;}
}
Seg.c
#include "Seg.h"code unsigned char seg_dula[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0x88,0xc6,0x8c};//0-9为数字,10为熄灭,11为A,12为C,13为P
code unsigned char seg_wela[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};void Seg_Disp(unsigned char wela,dula,point)
{P0 = 0xff;P2 = P2 & 0x1f | 0xe0;P2 &= 0x1f;P0 = seg_wela[wela];P2 = P2 & 0x1f | 0xc0;P2 &= 0x1f;P0 = seg_dula[dula];if(point) P0 &= 0x7f;P2 = P2 & 0x1f | 0xe0;P2 &= 0x1f;
}
Key.c
#include <Key.h>unsigned char Key_Read()
{unsigned char temp = 0;if (P33 == 0) temp = 4;if (P32 == 0) temp = 5;if (P31 == 0) temp = 6;if (P30 == 0) temp = 7;return temp;
}
onewire.c
#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;
}float rd_temperture(void)
{unsigned char low,high;init_ds18b20();Write_DS18B20(0xcc);Write_DS18B20(0x44);init_ds18b20();Write_DS18B20(0xcc);Write_DS18B20(0xbe);low = Read_DS18B20();high = Read_DS18B20();return ((high << 8) | low) / 16.0;
}
iic.c
#define DELAY_TIME 10
#include "iic.h"
#include "intrins.h"
sbit scl = P2 ^ 0;
sbit sda = P2 ^ 1;//
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);
}void Da_Write(unsigned char dat)
{I2CStart();I2CSendByte(0x90);I2CWaitAck();I2CSendByte(0x41);I2CWaitAck();I2CSendByte(dat);I2CWaitAck();I2CStop();
}
结语
至此本试题代码部分的笔记就完成了,有错误的地方感谢大家指出。
相关文章:
【蓝桥杯—单片机】第十一届省赛真题代码题解题笔记 | 省赛 | 真题 | 代码题 | 刷题 | 笔记
第十一届省赛真题代码部分 前言赛题代码思路笔记竞赛板配置内部振荡器频率设定键盘工作模式跳线扩展方式跳线 建立模板明确设计要求和初始状态显示功能部分数据界面第一部分第二部分第三部分调试时发现的问题 参数设置界面第一部分第二部分和第四部分第三部分和第五部分 按键功…...
hive的几种复杂数据类型
Hive的几种复杂数据类型 Hive 提供了几种复杂数据类型,能够支持更灵活和多样的数据存储。这些复杂数据类型对于处理嵌套数据或不规则数据特别有用。主要包括以下几种: 文章目录 Hive的几种复杂数据类型1. 数组(ARRAY)2. 结构体&a…...
使用 `WITH` 子句优化复杂 SQL 查询
使用 WITH 子句优化复杂 SQL 查询 在 SQL 中,处理复杂的查询需求时,代码往往会变得冗长且难以维护。为了解决这个问题,SQL 提供了 WITH 子句(也称为公用表表达式,Common Table Expression,CTE)…...
k8s网络插件及基础命令
一、k8s的cni网络插件 1.k8s的内部网络模式 pod内的容器与容器之间的通信。一个节点上的pod之间的通信,docker0网桥直接通信。不同节点上的pod之间的通信:通过物理网卡的ip地址和其他节点上的物理网卡的设备进行通信,然后把流量转发到指定的…...
组合总和II(力扣40)
这道题的难点就在于题目所给的集合中有重复的数字,我们需要进行去重操作。首先明确去重指的是去重哪一部分。注意并不是对递归的集合去重,而是对当前集合的遍历进行去重。这么说可能有点抽象,举个例子:假设集合为1,1,2,3,4&#x…...
【vue3 入门到实战】7. 标签中的 ref
目录 1. ref 的作用 2. 如何使用 1. ref 的作用 用于注册模板引用 用在普通DOM标签上,获取的是DOM节点。 用在组件标签上,获取的是组件的实例对象。 2. 如何使用 代码如下 <template><div class"app"><h2 ref"titl…...
MAC OS安装Homebrew
文章目录 1.下载Homebrew2.完成安装3.验证安装4.更新 Homebrew作为一个包管理器,提供了一种简便的方式来安装、更新和卸载各种命令行工具和应用程序。相比于手动下载和编译源代码,或者从不同的网站下载安装包,使用Homebrew可以显著减少这些操…...
数据结构之栈和队列(超详解)
文章目录 概念与结构栈队列 代码实现栈栈是否为空,取栈顶数据、栈的有效个数 队列入队列出队列队列判空,取队头、队尾数据,队列的有效个数 算法题解有效的括号用队列实现栈用栈实现队列复用 设计循环队列数组结构实现循环队列构造、销毁循环队…...
[Deepseek-自定义Ollama 安装路径+lmStudio 简易安装]
ollama 先下载 https://ollama.org.cn/download 使用 发现报错 检查路径 自己的路径! 再用 .\OllamaSetup.exe /DIRE:\MySoftware\Ollama 删除掉 多余模型 ollama delete <model_name> 例如 ollama delete deepseek-r1:1.5b 下载 ollama run deepseek-r1:1.5b…...
uniapp mqttjs 小程序开发
在UniApp中集成MQTT.js开发微信小程序时,需注意平台差异、协议兼容性及消息处理等问题。以下是关键步骤与注意事项的综合指南: 一、环境配置与依赖安装 安装MQTT.js 推荐使用兼容性较好的版本:mqtt4.1.0(H5和小程序兼容性最佳&…...
LabVIEW位移测量系统
本文介绍了一种基于LabVIEW的位移测量系统,结合先进的硬件设备与LabVIEW平台的强大功能,能够实现对位移的精确测量和高效数据处理。该系统具备高精度、实时性和良好的可扩展性,适用于工程与科学实验中对位移测量的多种需求。 项目背景 位移…...
VMware下Linux和macOS遇到的一些问题总结
1.解决.NET程序通过网盘传到Linux和macOS不能运行的问题 这是文件权限的问题。当你通过U盘将文件传输到虚拟机的macOS和Linux系统时,文件的权限和所有权可能得到了保留或正确设置。但如果你通过网盘上传,文件的权限或所有权可能没有正确设置,…...
Mac: docker安装以后报错Command not found: docker
文章目录 前言解决办法(新的)解决步骤(原来的)不推荐总结 前言 本操作参考 http://blog.csdn.net/enhenglhm/article/details/137955756 原作者,更详细请,查看详细内容请关注原作者。 一般,…...
深度学习里面的而优化函数 Adam,SGD,动量法,AdaGrad 等 | PyTorch 深度学习实战
前一篇文章,使用线性回归模型逼近目标模型 | PyTorch 深度学习实战 本系列文章 GitHub Repo: https://github.com/hailiang-wang/pytorch-get-started 本篇文章内容来自于 强化学习必修课:引领人工智能新时代【梗直哥瞿炜】 深度学习里面的而优化函数 …...
C++自研3D教程OPENGL版本---动态批处理的基本实现
又开始找工作了,借机休息出去旅行两个月,顺便利用这段时间整理下以前写的东西。 以下是一个简单的动态批处理实现: #include <GL/glew.h> #include <GLFW/glfw3.h> #include <iostream> #include <vector>// 顶点结…...
如何使用deepseek开发一个翻译API
什么是deepseek Deepseek 是一个基于人工智能技术的自然语言处理平台,提供了多种语言处理能力,包括文本翻译、语义分析、情感分析等。它通过深度学习模型和大规模语料库训练,能够实现高质量的文本翻译和多语言理解。Deepseek 的核心优势在于…...
Java使用aspose实现pdf转word
Java使用aspose实现pdf转word 一、下载aspose-pdf-21.6.jar包【下载地址】,存放目录结构如图;配置pom.xml。 <!--pdf to word--> <dependency><groupId>com.aspose</groupId><artifactId>aspose-pdf</artifactId>…...
fs 文件系统模块
在 Node.js 中,fs(File System)模块提供了与文件系统进行交互的能力。无论是读取、写入还是操作文件和目录,fs 模块都提供了丰富的 API 支持。本文将详细介绍 fs 模块的基本用法、异步与同步方法的区别以及一些高级功能࿰…...
正激变换器拓扑
正激变换器拓扑是一种常见的DC-DC电源拓扑结构,以下是关于它的详细介绍: 基本组成 - 主开关:通常为MOSFET,用于控制输入电压的通断。 - 变压器:实现电压隔离和电压变换,传递能量。 - 续流二极管&#x…...
Rsyslog omhttp(HTTP输出模块)
个人博客地址:Rsyslog omhttp(HTTP输出模块) | 一张假钞的真实世界 使用Rsyslog的omhttp模块可以将收集的日志数据以HTTP请求的方式输出。该模块支持单条/批量发送数据,支持GZIP压缩,支持HTTPS。 Rsyslog默认未包含o…...
防火墙与Squid代理服务器
服务器的安装、搭建与配置准备前期 虚拟机版本:redhat Enterprise Linux Server release 7.2(Maipo)系统架构:x86虚拟机服务器地址:192.168.195.3Window地址:192.168.195.237进行ISO挂载操作进入root模式[yonghu@localhost 桌面]#su 返回上级目录文件进入media文件中,创建…...
为何实现大语言模型的高效推理以及充分释放 AI 芯片的计算能力对于企业级落地应用来说,被认为具备显著的研究价值与重要意义?
🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ AI 芯片:为人工智能而生的 “大脑” AI 芯片,又称人工智能加速器或计算卡,是专为加速人工智能应用,特别是深度学习任务设计的专用集成电路(A…...
【教程】docker升级镜像
转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~ 目录 自动升级 手动升级 无论哪种方式,最重要的是一定要通过-v参数做数据的持久化! 自动升级 使用watchtower,可…...
k8s常见面试题2
k8s常见面试题2 安全与权限RBAC配置如何保护 Kubernetes 集群的 API Server?如何管理集群中的敏感信息(如密码、密钥)?如何限制容器的权限(如使用 SecurityContext)?如何防止容器逃逸࿰…...
mysql运维
1、msyqlLinux通用二进制安装 1. MySQL :: Download MySQL Community Server (Archived Versions)https://downloads.mysql.com/archives/community/https://downloads.mysql.com/archives/community/https://downloads.mysql.com/archives/community/https://downloads.mysql…...
将Deepseek接入pycharm 进行AI编程
目录 专栏导读1、进入Deepseek开放平台创建 API key 2、调用 API代码 3、成功4、补充说明多轮对话 总结 专栏导读 🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手 🏳️🌈 博客主页:请点击——…...
Redis03 - 高可用
Redis高可用 文章目录 Redis高可用一:主从复制 & 读写分离1:主从复制的作用2:主从复制原理2.1:全量复制2.2:增量复制(环形缓冲区) 3:主从复制实际演示3.1:基本流程准…...
日常知识点之面试后反思遗留问题汇总
梳理一下最近接触到的几个知识点: 1:突然问到端口复用 (SO_REUSEADDR) 端口复用一般用在服务端重启时,套接字处于time_wait状态时,无法绑定该端口,导致无法启动问题。 设置端口复用ÿ…...
软考教材重点内容 信息安全工程师 第15章 网络安全主动防御技术与应用
目录 15.1.1 人侵阻断技术原理 15.1.2 人侵阻断技术应用 15.3 网络流量清洗技术与应用 15.3.1 网络流量清洗技术原理 15.3.2 网络流量清洗技术应用 15.4 可信计算技术与应用 15.4.1 可信计算技术原理 15.5 数字水印技术与应用 15.5.1 数字水印技术原理 15.5.2 数字水…...
大模型的底层逻辑及Transformer架构
一、大模型的底层逻辑 1.数据驱动 大模型依赖海量的数据进行训练,数据的质量和数量直接影响模型的性能。通过大量的数据,模型能够学习到丰富的模式和规律,从而更好地处理各种任务。 2.深度学习架构 大模型基于深度学习技术,通常采用多层神经网络进行特征学习与抽象。其中…...
PostgreSQL-字符串函数
字符串连接 SELECT A||B; 字符串连接,适用于字符串与数字连接 SELECT CONCAT(10,a,hello,20.0); 连接所有参数,个数不限,类型不限 字母转换 SELECT LOWER(ABCD); 将字符转换成小写 SELECT UPPER(ABCD); 将字符转换成大写 SELECT IN…...
Qt修仙之路2-1 炼丹初成
widget.cpp #include "widget.h" #include<QDebug> //实现槽函数 void Widget::login1() {QString userusername_input->text();QString passpassword_input->text();//如果不勾选无法登入if(!check->isChecked()){qDebug()<<"xxx"&…...
华为的IPD模式VS敏捷项目管理模式
本文介绍了华为的IPD模式与敏捷项目管理模式的对比。文章详细阐述了两种模式的特点、适用范围及实施要点,为读者提供了全面的理解。 重点内容: 1. IPD模式强调跨部门协同,注重产品全生命周期管理,适用于复杂产品领域。 2. 敏捷…...
Ollama python交互:chat+embedding实践
Ollama简介 Ollama 是一个开源的大型语言模型(LLM)平台,旨在让用户能够轻松地在本地运行、管理和与大型语言模型进行交互。 Ollama 提供了一个简单的方式来加载和使用各种预训练的语言模型,支持文本生成、翻译、代码编写、问答等…...
Redis进阶
Redis持久化: 前面我们讲到mysql事务有四个比较核心的特性: 原子性:保证多个操作打包成一个。一致性:A给B100,A少一百,B必须多一百。持久性:针对事务操作必须要持久生效,不管是重启…...
【蓝桥杯嵌入式】6_定时器输入捕获
全部代码网盘自取 链接:https://pan.baidu.com/s/1PX2NCQxnADxYBQx5CsOgPA?pwd3ii2 提取码:3ii2 这是两个信号发生器,可以通过调节板上的两个电位器R39和R40调节输出频率。 将PB4、PA15选择ch1,两个信号发生器只能选择TIM3和TIM…...
C#常用集合优缺点对比
先上结论: 在C#中,链表、一维数组、字典、List<T>和ArrayList是常见的数据集合类型,它们各有优缺点,适用于不同的场景。以下是它们的比较: 1. 一维数组 (T[]) 优点: 性能高:数组在内存中…...
Python调取本地MongoDB招投标数据库,并结合Ollama部署的DeepSeek-R1-8B模型来制作招投标垂直领域模型
根据你的需求,以下是使用Python调取本地MongoDB招投标数据库,并结合Ollama部署的DeepSeek-R1-8B模型来制作招投标垂直领域模型的步骤: 安装PyMongo 首先,确保你已经安装了PyMongo库,用于Python与MongoDB的交互。如果未…...
【MySQL】深入了解索引背后的内部结构
目录 索引的认识: 作用: 索引的使用: 索引底层的数据结构: 哈希表 AVL树 红黑树 B树: B树: B树搜索: 索引的认识: 索引是数据库中的一个数据结构,用于加速查询…...
pytest-xdist 进行多进程并发测试
在自动化测试中,运行时间过长往往是令人头疼的问题。你是否遇到过执行 Pytest 测试用例时,整个测试流程缓慢得让人抓狂?别担心,pytest-xdist 正是解决这一问题的利器!它支持多进程并发执行,能够显著加快测试…...
蓝桥杯准备 【入门3】循环结构
素数小算法(埃氏筛&&欧拉筛) 以下四段代码都是求20以内的所有素数 1.0版求素数 #include<iostream> using namespace std;int main() {int n 20;for(int i2;i<n;i){int j0;for(j2;j<i;j)//遍历i{if(i%j0){break;}}if(ij){cout&l…...
PHP填表统计预约打卡表单系统小程序
📋 填表统计预约打卡表单系统——专属定制,信息互动新纪元 📊 填表统计预约打卡表单系统,一款专为现代快节奏生活量身打造的多元化自定义表单统计小程序,集信息填表、预约报名、签到打卡、活动通知、报名投票、班级统…...
自定义数据集,使用scikit-learn 中K均值包 进行聚类
1. 引言 K均值聚类是一种无监督学习方法,用于将数据集分为多个簇。通过计算数据点之间的距离并将它们分配到最近的簇中心,K均值算法可以帮助我们发现数据中的自然结构。 2. 数据集创建 首先,我们使用numpy创建一个自定义的二维数据集&…...
Lua中文语言编程源码-第十一节,其它小改动汉化过程
__tostring 汉化过程 liolib.c metameth[] {"__转换为字符串", f_tostring}, lauxlib.c luaL_callmeta(L, idx, "__转换为字符串") lua.c luaL_callmeta(L, 1, "__转换为字符串") __len 汉化过程 ltm.c luaT_eventname[] ltablib.c c…...
Android studio 创建aar包给Unity使用
1、aar 是什么? 和 Jar有什么区别 aar 和 jar包 都是压缩包,可以使用压缩软件打开 jar包 用于封装 Java 类及其相关资源 aar 文件是专门为 Android 平台设计的 ,可以包含Android的专有内容,比如AndroidManifest.xml 文件 &#…...
4. 【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--什么是微服务--微服务设计原则与最佳实践
相比传统的单体应用,微服务架构通过将大型系统拆分成多个独立的小服务,不仅提升了系统的灵活性和扩展性,也带来了许多设计和运维上的挑战。如何在设计和实现微服务的过程中遵循一系列原则和最佳实践,从而构建一个稳定、高效、易维…...
大语言模型遇上自动驾驶:AsyncDriver如何巧妙解决推理瓶颈?
导读 这篇论文提出了AsyncDriver框架,致力于解决大语言模型在自动驾驶领域应用中的关键挑战。论文的主要创新点在于提出了大语言模型和实时规划器的异步推理机制,实现了在保持性能的同时显著降低计算开销。通过设计场景关联指令特征提取模块和自适应注入…...
第17章 读写锁分离设计模式(Java高并发编程详解:多线程与系统设计)
1.场景描述 对资源的访问一般包括两种类型的动作——读和写(更新、删除、增加等资源会发生变化的动作),如果多个线程在某个时刻都在进行资源的读操作,虽然有资源的竞争,但是这种竞争不足以引起数据不一致的情况发生,那么这个时候…...
硬盘修复后,文件隐身之谜
在数字时代,硬盘作为数据存储的重要载体,承载着无数珍贵的信息与回忆。然而,当硬盘遭遇故障并经过修复后,有时我们会遇到这样一个棘手问题:硬盘修复后,文件却神秘地“隐身”,无法正常显示。这一…...
Ollama+ page Assist或Ollama+AnythingLLM 搭建本地知识库
参考:【AI】10分钟学会如何用RAG投喂数据给你的deepseek本地模型?_哔哩哔哩_bilibili 方法一:Ollama page Assist 本地知识库 ***下方操作比较精简,详情参考:Ollama 部署本地大语言模型-CSDN博客 1.下载Ollama 2.O…...