【蓝桥杯—单片机】第十五届省赛真题代码题解析 | 思路整理

第十五届省赛真题代码题解析

  • 前言
  • 赛题代码思路笔记
    • 竞赛板配置
    • 建立模板
    • 明确基本要求
    • 显示功能部分
      • 频率界面
        • 正常显示
        • 高位熄灭
      • 参数界面
        • 基础写法:两个界面分开来写
        • 优化写法:两个界面合一起写
      • 时间界面
      • 回显界面
      • 校准
        • 校准过程
        • 校准错误显示
    • DAC输出部分
    • 按键功能部分
        • S4:“界面”按键
        • S5:“选择”按键
          • 优化写法
        • S8、S9:“加”按键 、“减”按键
      • LED指示灯功能部分
      • 调试时发现的问题
  • 最终代码
    • User文件
      • main.c
    • Driver文件
      • init.c
      • Key.c
      • Led.c
      • Seg.c
      • iic.c
      • ds1302.c
    • 结语

前言

本文是对蓝桥杯第十五届省赛真题的代码题做的解题笔记。
我在看完西风老师的解析视频后,自己重新写了一遍,做了点整理也加入了一点个人的思考,因此在细节上(比方说:变量名…)会有一点出入。

思路参考西风第二十三讲内容(资料链接已经在下方给出)

https://www.bilibili.com/video/BV1TR4y1k7iz?p=23&vd_source=e2191f89c557f5ac44bb6c7aa3967c7c

关于蓝桥杯第十五届省赛真题可以在官网查看(资料链接已经在下方给出)

https://www.lanqiao.cn/courses/2786/learning/?id=2870978&compatibility=false

赛题代码思路笔记

竞赛板配置

在这里插入图片描述

建立模板

根据赛题中的硬件框图确定本赛题的框架
在这里插入图片描述
如图,在Driver文件夹里建立LED、数码管、按键、iic模块(DAC输出)、DS1302,在User文件夹中建立主函数模块(大模板参考西风老师的2024版大模板)。
在这里插入图片描述

明确基本要求

在这里插入图片描述
在这里插入图片描述


注意1.的内容:

  • P34引脚和矩阵按键有冲突,写按键模块(Key.h)时注意屏蔽掉P34=0的情况
  • 板子的P34口和SIGNAL的跳帽要接上

在这里插入图片描述
注意2.的内容:

  • 按键延迟时间要控制在100ms以内
	/*按键10ms的减速*/if(Slow_Down % 10 == 0){Key_Flag = 0;}

在这里插入图片描述
注意第三点的内容:

  • 数码管延迟时间要控制在100ms以内
    /*数码管90ms的减速*/if(++Slow_Down == 90){Seg_Flag = Slow_Down = 0;}

在这里插入图片描述

显示功能部分

在这里插入图片描述

在这里插入图片描述

  1. 显示部分一共4个界面,定义一个变量界面显示模式变量Seg_Disp_Mode各个界面。
    后续通过对 Seg_Disp_Mode (界面显示模式变量)的判断切换不同的界面。
unsigned char Seg_Disp_Mode;           //界面显示模式变量 0-频率界面 1-参数界面 2-时间界面 3-回显界面
	switch(Seg_Disp_Mode){case 0://频率界面break;case 1://参数界面break;case 2://时间界面break;case 3://回显界面break;}
  1. 在显示功能部分中,需要显示的字符有:0-9、熄灭、A、F、H、P、-,在seg.c文件段选数组中添加对应的十六进制表示。
code unsigned char Seg_dula[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0x88,0x8e,0x89,0x8c,0xBF};//0-9,10-熄灭,11-A,12-F,13-H,14-P,15--

频率界面

在这里插入图片描述

频率界面由三部分组成:

  • 第一部分为编号(Seg_Buf[0]),在该界面下全程显示字母F。
  • 第二部分熄灭部分(Seg_Buf[1] - Seg_Buf[2]),在该界面下全程熄灭。
  • 第三部分为频率显示部分(Seg_Buf[3] - Seg_Buf[7]),用NE555实时计算频率。
正常显示

数码管显示数组Seg_Buf[])对应的数码管中输入要显示的字符在seg.c文件段选数组Seg_dula[])对应的十六进制表示的位置。

			Seg_Buf[0] = 12;//FSeg_Buf[1] = Seg_Buf[2] = 10;Seg_Buf[3] = Freq / 10000 % 10;Seg_Buf[4] = Freq / 1000 % 10;Seg_Buf[5] = Freq / 100 % 10;Seg_Buf[6] = Freq / 10 % 10;Seg_Buf[7] = Freq % 10;
高位熄灭

在这里插入图片描述
while循环高位开始检测,当高位是0时,将该位置的数码管置为熄灭状态。

注意:
显示最小为0,即数码管的最后一位(Seg_Buf[7])不论是否为0都要保证正常显示,所以在while循环中不对最后一位检测。

	unsigned char i=3;/*高位为0时熄灭*/while(Seg_Buf[i] == 0){Seg_Buf[i] = 10;if(++i == 7) break;}break;

参数界面

在这里插入图片描述
参数界面中又有两个子界面,定义参数界面模式变量Seg_DM1_Mode对两个子界面标记。

bit Seg_DM1_Mode = 1;                      //参数界面模式变量 0-超限参数界面 1-校准值参数界面

定义参数数组Seg_Set_Arr,存储两个界面下的参数值。
介于校准值界面的参数值有负数的情况,可以将参数数组(Seg_Set_Arr)直接定义为有符号的数组,后续只要对校准值变量的正负进行判断就可以确定校准值的符号位要不要点亮。

int Seg_Set_Arr[2] = {2000,0};         //参数数组 [0]-超限参数 [1]-校准值变量
基础写法:两个界面分开来写
  1. if 判断当前子界面:Seg_DM1_Mode(参数界面模式变量)为0,处于超限参数界面;反之,处于校准值参数界面。
  2. 超限参数界面(逻辑和频率界面的正常显示部分相同,不再赘述)
  3. 校准值参数界面时:
    用if检测校准值,分为校准值参数不为0校准值参数为0两种情况。
    校准值参数不为0时:用一组 if 判断校准值的正负性,先确定符号位,再对数值进行显示。
    注意:校准值是有符号的数据,要取出各位数可以对他先取它的绝对值(math.h文件中的abs函数
    当校准值参数为0时:显示一位0。
#include "math.h"  //abs函数
 		    if(Seg_DM1_Mode == 0)//超限参数界面{Seg_Buf[4] = Seg_Set_Arr[0] /1000 % 10;Seg_Buf[5] = Seg_Set_Arr[0] /100 % 10;Seg_Buf[6] = Seg_Set_Arr[0] /10 % 10;Seg_Buf[7] = Seg_Set_Arr[0] % 10;}else//校准值参数界面{if(Seg_Set_Arr[1] != 0){/*确定符号位*/if(Seg_Set_Arr[1] < 0)Seg_Buf[4] = 15;//-else Seg_Buf[4] = 10;//熄灭Seg_Buf[5] = abs(Seg_Set_Arr[1]) /100 % 10;Seg_Buf[6] = abs(Seg_Set_Arr[1]) /10 % 10;Seg_Buf[7] = abs(Seg_Set_Arr[1]) % 10;}else{Seg_Buf[5] = Seg_Buf[6] = 10;Seg_Buf[7] = 0;}				}
优化写法:两个界面合一起写

(这个部分是我对本套题解析视频做的笔记,西风老师这个写法的思路真的蛮好的)

先看到具体代码:

		Seg_Buf[0] = 14;//PSeg_Buf[1] = (unsigned char)Seg_DM1_Mode+1;Seg_Buf[2] = Seg_Buf[3] = 10;Seg_Buf[4] = Seg_DM1_Mode?(10 + 5 * (Seg_Set_Arr[Seg_DM1_Mode] < 0)):abs(Seg_Set_Arr[Seg_DM1_Mode]) /1000 % 10;Seg_Buf[5] = abs(Seg_Set_Arr[Seg_DM1_Mode]) /100 % 10;Seg_Buf[6] = abs(Seg_Set_Arr[Seg_DM1_Mode]) /10 % 10;Seg_Buf[7] = abs(Seg_Set_Arr[Seg_DM1_Mode]) % 10;/*校准值为0时,只显示一位0*/if(Seg_Set_Arr[Seg_DM1_Mode] == 0)Seg_Buf[5] = Seg_Buf[6] = 10;

优化写法重点在于:

  1. Seg_DM1_Mode(参数界面模式变量)和显示相关变量的代数关系
  2. 条件运算符

简单回顾一下条件运算符:
<表达式1>?<表达式2>:<表达式3>
当表达式1为真,返回表达式2的值;如果为假,则返回表达式3的值。

基础的显示不再赘述,在此对 Seg_Buf[1]Seg_Buf[4] 做简单的分析:

  1. Seg_Buf[1]:
    由题目所给信息可知,Seg_Buf[1]在1和2之间变化,对应的是两个子界面
    在此前我们已经给这两个界面定义好了标志变量Seg_DM1_Mode(参数界面模式变量),它在0和1之间变化
    不难得出,Seg_Buf[1]和Seg_DM1_Mode之间的代数关系,即Seg_Buf[1]的值比Seg_DM1_Mode大1
    注意: Seg_DM1_Mode是bit型数据,不能到达2,所以让Seg_DM1_Mode直接+1不能达到效果。那么需要解决的问题是增大它数值的可变区间,可以用强制类型转换。
  2. Seg_Buf[4]:
    Seg_Buf[4]对应了两种显示状态,即超限参数界面下的高位校准值参数界面下的符号位
    条件运算符对Seg_DM1_Mode(参数界面模式变量)进行判断,可以划分出两种状态,即当Seg_DM1_Mode为真(Seg_DM1_Mode为1)时,是校准值参数界面;当Seg_DM1_Mode为假(Seg_DM1_Mode为0)时,是超限参数界面。
    那么,只要找出Seg_Buf[4]在两种显示状态下的数值在段选数组(Seg.h文件下的Seg_dula[])中的位置就可以完成显示。
    Seg_Buf[4]在超限参数界面下的高位状态时(Seg_DM1_Mode为0):只要获取超限参数(Seg_Set_Arr[0])的最高位就行。
    Seg_Buf[4]在校准值参数界面下的符号位状态时(Seg_DM1_Mode为1):Seg_Buf[4]在Seg_Set_Arr[1](校准值参数)为正,Seg_Buf[4]不点亮;Seg_Set_Arr[1](校准值参数)为负,Seg_Buf[4]才点亮,显示符号位。所以还要找熄灭对应的位置和负号对应的位置之间的关系
    这里我觉得比较妙的一点是用条件是否为真(Seg_Set_Arr[Seg_DM1_Mode] < 0)进行了熄灭和负号点亮之间的切换。)

时间界面

在这里插入图片描述
在这里插入图片描述
定义**时间参数数组ucRtc[]**用来存储时分秒的数据。

unsigned char ucRtc[3] = {13,03,05};   //时间参数数组 [0]-时 [1]-分 [2]-秒

调用ds1302里写入的函数Set_Rtc(),将初始显示状态的数据在上电时写入

	Set_Rtc(ucRtc);

每次进入信息处理函数时读取(Read_Rtc())时钟信息更新时间参数数组ucRtc[] 的数据,为后续显示做准备。

	Read_Rtc(ucRtc);

(显示可以一位数码管一位数码管写,和频率界面的正常显示相似,就不再赘述了。)
for循环 将数码管显示的时分秒数据写入。
这里要找出时分秒在数码管的位置之间的代数关系,时分秒的高位分别占0 3 6,低位占1 4 7,可知高位满足 y = 3x ,低位满足 y = 3x+1。
在一次循环里实现一组高低位的取值。

			for(j = 0;j < 3;j++){Seg_Buf[j * 3] = ucRtc[j] / 10;Seg_Buf[j * 3 + 1] = ucRtc[j] %10;}Seg_Buf[2] = Seg_Buf[5] = 15;//-

回显界面

在这里插入图片描述
回显界面也有两个子界面,声明回显界面模式变量bit Seg_DM3_Mode标记两个子界面。
频率回显界面要显示最大频率值,时间回显界面要显示最大频率发生时间,分别声明最大频率值变量Max_Freq和**最大频率发生时间数组Max_Freq_Time[3]**存储这两个值。

bit Seg_DM3_Mode;                      //回显界面模式变量 0-频率回显界面 1-时间回显界面
unsigned int Max_Freq;                 //最大频率值变量
unsigned int Max_Freq_Time[3];          //最大频率发生时间数组

每次进入信息处理函数后获取最大频率及其发生时间,存到对应的变量里,以供后续调用。

/*获取最大频率及其发生时间*/if(Max_Freq < Freq){Max_Freq = Freq;for(j = 0;j < 3;j ++)Max_Freq_Time[j] = ucRtc[j];}

频率回显界面要注意高位熄灭
时间回显界面用循环获取时间的话,和时间界面相似,要找出各位之间的代数关系。

			Seg_Buf[0] = 13;//Hif(Seg_DM3_Mode == 0)//频率回显界面{Seg_Buf[1] = 12;//FSeg_Buf[2] = 10;Seg_Buf[3] = Max_Freq / 10000 % 10;Seg_Buf[4] = Max_Freq / 1000 % 10;Seg_Buf[5] = Max_Freq / 100 % 10;Seg_Buf[6] = Max_Freq / 10 % 10;Seg_Buf[7] = Max_Freq % 10;/*高位为0时熄灭*/while(Seg_Buf[i] == 0){Seg_Buf[i] = 10;if(++i == 7) break;}}else//时间回显界面{Seg_Buf[1] = 11;//Afor(j = 0;j < 3;j ++){Seg_Buf[2+2*j] =  Max_Freq_Time[j] / 10;Seg_Buf[2+2*j+1] =  Max_Freq_Time[j] % 10;}}

校准

在这里插入图片描述

校准过程

显示的频率都是实时频率加上校准值后的结果,那么只要在计算完频率之后加上校准值即可。

Freq += Seg_Set_Arr[1];  //加上校准值
校准错误显示

校准错误显示在频率显示界面(Seg_Disp_Mode为0)下实现
可以将显示分为两种情况

  1. 频率正常
  2. 频率错误

if 对校准后的频率进行判断,当频率大于0时,正常读取正常显示;当频率小于0时,只显示首位的编号和末两位的LL。

		if(Freq >= 0){Seg_Buf[3] = Freq / 10000 % 10;Seg_Buf[4] = Freq / 1000 % 10;Seg_Buf[5] = Freq / 100 % 10;Seg_Buf[6] = Freq / 10 % 10;Seg_Buf[7] = Freq % 10;/*高位为0时熄灭*/while(Seg_Buf[i] == 0){Seg_Buf[i] = 10;if(++i == 7) break;}}else{Seg_Buf[3] = Seg_Buf[4] = Seg_Buf[5] = 10;//熄灭Seg_Buf[6] = Seg_Buf[7] = 16;//LL} 

注意: Freq要用 long int型
考虑两个点 :

  1. 频率的正负。因为加上校验值后频率可能为负数,如果用无符号型无论如何都得不到负数,所以要用有符号型的数据。
  2. 范围。int型的取值范围为 -32768 到 32767 ,用来存储单纯的频率是够用的,但是加上校验值后就可能产生数据溢出的问题,使得显示数据不准,所以要扩大取值范围

DAC输出部分

在这里插入图片描述
在这里插入图片描述
声明输出电压变量V_OutPut,存储要输出的电压大小。

float V_OutPut;                         //输出电压变量

整体的输出可以把分成四段:

  1. 频率错误(Frqe<0)时,DAC输出0V。
  2. 频率大于等于0且小于500Hz时,DAC输出1V
  3. 频率大于超限参数时,DAC输出5V
  4. 频率在500Hz和超过限制频率之间时,DAC输出要求出该斜线的表达式。
    易得数学表达式:
    V = ( ( 5 - 1 ) / ( 超限参数 - 500 ) ) * (F-500) + 1
  5. 频率错误时,DAC输出0V。

注意: V_OutPut(输出电压变量)写入的 0-5 的值是需要输出的模拟输出值,而在调用DAC输出函数(Da_Write)时写入的参数是 0 - 255 范围内的数字输入值。如果直接用V_OutPut的值写入参数,那么实际输出的电压值将会很小,所以在此要将 0-5 范围的值线性映射成 0-255 范围的量值,不难得出这两个范围的倍数关系是51,因此只要对小的值(输出电压变量V_OutPut)乘上51即可完成映射。

/*DAC相关*/if(Freq < 0) V_OutPut = 0;else if(Freq >= 0 && Freq <= 500) V_OutPut = 1;else if(Freq >= Seg_Set_Arr[0]) V_OutPut = 5;else V_OutPut = 1 + (float)(5.0 - 1.0)/(Seg_Set_Arr[0] - 500) * (Freq - 500);Da_Write(V_OutPut * 51);

按键功能部分

在这里插入图片描述
在这里插入图片描述

/*按键处理函数*/
void Key_Proc()
{if(Key_Flag) return;Key_Flag = 1;Key_Val = Key_Read();Key_Down = Key_Val & (Key_Val ^ Key_Old);Key_Old = Key_Val;switch(Key_Down){case 4://“界面”按键break;case 5://“选择”按键break;case 8://“加”按键break;case 9://“减”按键break;}
}
S4:“界面”按键

在这里插入图片描述

界面切换要考虑模式变量的取值情况
按键按下一次模式切换一次,即 Seg_Disp_Mode(界面显示模式变量)+1。Seg_Disp_Mode在 0-3 之间变化,对应4个模式,最大值不能为3,所以当 Seg_Disp_Mode 加到4时,要将它重新赋0,以此形成一个循环的切换

if(++Seg_Disp_Mode == 4) Seg_Disp_Mode = 0;
S5:“选择”按键

在这里插入图片描述
分成两种情况对各自界面下的模式变量操作。
因为这两个界面下的模式变量都是bit型,可以不用像“界面”按键那里一样进行加法操作,可以用异或。
这里用异或,其实就相当于取反。因为bit型数据本身就只有0和1两个数值,0异或后为1,1异或后为0。

			if(Seg_Disp_Mode == 1)Seg_DM1_Mode ^= 1;else if(Seg_Disp_Mode == 3)Seg_DM3_Mode ^= 1;

注意:

  1. 频率界面切换到参数界面和时间界面切换到回显界面时,有默认显示的子界面,所以在每次在完成这两种切换时,都要保证当前显示处于默认子界面,但是在上面的操作中并不能实现。
  2. 默认子界面的显示是在按下“界面”按键时生效的(Key_Down为4),即要对“界面”按键按下后将要显示的界面进行判断,决定是否要重置子界面的模式变量
            if(++Seg_Disp_Mode == 1)  Seg_DM1_Mode = 0;   //默认显示超限参数子界面if(Seg_Disp_Mode == 3)  Seg_DM3_Mode = 0;     //默认显示频率回显子界面if(Seg_Disp_Mode == 4)  Seg_Disp_Mode = 0;    //退回到最初界面
优化写法

上面是对按键按下后的界面进行了判断后才执行重置。但是,其实不进行判断也是可以的。因为子界面模式变量的值是多少对于另外两个界面的显示没有任何影响,所以可以省去判断的那一步,在每次按下按键就重置。

			if(++Seg_Disp_Mode == 4) Seg_DM1_Mode = Seg_DM3_Mode = Seg_Disp_Mode = 0;
S8、S9:“加”按键 、“减”按键

在这里插入图片描述

在这里插入图片描述
“加”按键和“减”按键逻辑类似,此处只对“加”按键做简单的解析。
在进行加法运算时,要考虑单次加的单位值大小参数的上限值
此处是对同界面下的两个子界面的参数进行的加法,所以可以将两个子界面的单次加的单位值和参数上限值分组后分别存在两个数组中(单次加减大小数组Step_Arr[2]上限值数组Max_Arr[2]),前一个数是超限参数对应的值,后一个数是校准参数对应的值。

//按键功能相关变量
int code Step_Arr[2] = {1000,100};     //单次加减大小数组 [0]-超限参数单次增加量/减小量 [1]-校准参数单次增加量/减小量
int code Max_Arr[2] = {9000,900};      //上限值数组 [0]-超限参数上限值 [1]-校准参数上限值
int code Min_Arr[2] = {1000,-900};     //下限值数组 [0]-超限参数下限值 [1]-校准参数下限值

通过参数界面模式变量(Seg_DM1_Mode) 根据当前界面的不同获取对应的值,进行加法处理。
每次加完都要对当前数值进行判断,避免超出限制
(减法运算逻辑类似,不赘述)

			case 8://“加”按键if(Seg_Disp_Mode == 1 ){Seg_Set_Arr[Seg_DM1_Mode] += Step_Arr[Seg_DM1_Mode];if(Seg_Set_Arr[Seg_DM1_Mode] > Max_Arr[Seg_DM1_Mode])Seg_Set_Arr[Seg_DM1_Mode] = Max_Arr[Seg_DM1_Mode];}break;case 9://“减”按键if(Seg_Disp_Mode == 1 ){Seg_Set_Arr[Seg_DM1_Mode] -= Step_Arr[Seg_DM1_Mode];if(Seg_Set_Arr[Seg_DM1_Mode] < Min_Arr[Seg_DM1_Mode])Seg_Set_Arr[Seg_DM1_Mode] = Min_Arr[Seg_DM1_Mode];}break;

LED指示灯功能部分

在这里插入图片描述
这块的重点是两个地方:

  1. 0.2s间隔的闪烁。
  2. 亮、灭状态的切换。

声明闪烁间隔计时变量Time_200ms,后续用于0.2间隔闪烁的计时。
声明闪烁标志位Led_Flag,用于标记亮灭状态,并且通过它的改变实现亮灭的切换。

//LED指示灯功能相关变量
unsigned char Time_200ms;              //闪烁间隔计时变量
bit Led_Flag;                          //闪烁标志位

在定时中断服务函数中完成。
每计时满200ms重新开始计时,并且改变一次亮灭状态。

/*LED闪烁200ms计时*/if(++Time_200ms == 200){Time_200ms = 0;Led_Flag ^= 1;}

(在实现点亮时,可以用最基础的 if 的方式一步一步判断,这个逻辑很简单,暂时先不写了。下面这个是西风老师的逻辑,我认为比最基础版写法更好,因为更能体现你对C语言运算符运用,对此我做个简要的分析一下)
题目涉及的LED只有L1和L2,所以只要对Led控制数组(ucLed[])前两位进行操作。

  1. L1在频率界面下生效(Seg_Disp_Mode为0),用逻辑非运算符( !) 对 Seg_Disp_Mode 的逻辑值取反。即Seg_Disp_Mode为 0时(当前处于频率界面),那逻辑值就是假,! 运算之后的结果就是 1;Seg_Disp_Mode若不为 0(当前不处于频率界面),那逻辑值就是真,! 运算之后的结果就是 0。
    再和闪烁标志位(Led_Flag)进行逻辑与(有0出0)的运算,那么当Seg_Disp_Mode为 0时(当前处于频率界面),L1的点亮状态全由 Led_Flag(闪烁标志位)决定
  2. L2在频率大于超限参数 或者 频率为负数时生效,因为两种情况中任意满足一种它就生效,所以可以对这两个情况进行逻辑或运算(其中一个操作数的逻辑值为真,整个表达式的结果就为真)。
    处于频率大于超限参数时,在这可以直接对频率判断 也 可以对DAC输出电压变量(V_OutPut)进行判断。对 V_OutPut 判断(回顾DAC输出部分),当 V_OutPut 为 5 时表示当前处于频率大于超限参数的状态,要实现L2闪烁。那么只要对 V_OutPut == 5 进行真假逻辑的判断就可以用1和0来表示 频率大于超限参数(L2闪烁)频率不大于超限参数(L2不闪烁) 两种情况。此时就和L1的思路相似,将 V_OutPut == 5 逻辑真假的输出值和闪烁标志位(Led_Flag)进行逻辑与(有0出0)的运算,那么当逻辑为真(频率大于超限参数(L2闪烁))时,L2 的点亮状态全由 Led_Flag(闪烁标志位)决定。
    处于频率为负数时,直接对Freq < 0进行逻辑判断,那么当频率为负数是输出为1,此时L1点亮。
	/**LED相关**/ucLed[0] = Led_Flag & (!Seg_Disp_Mode);ucLed[1] = (Led_Flag & (V_OutPut == 5)) || (Freq < 0);

调试时发现的问题

最终代码

User文件

main.c

/*头文件声明区*/
#include <STC15F2K60S2.H>
#include "Init.h"
#include "Seg.h"
#include "Key.h"
#include "Led.h"
#include "iic.h"
#include "ds1302.h"
#include "math.h"/*变量声明区*/
unsigned char Key_Down,Key_Val,Key_Up,Key_Old;
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};
unsigned int Slow_Down;
bit Seg_Flag,Key_Flag;
unsigned int Time_1s;
long int Freq;//界面相关变量
unsigned char Seg_Disp_Mode;           //界面显示模式变量 0-频率界面 1-参数界面 2-时间界面 3-回显界面
bit Seg_DM1_Mode;                      //参数界面模式变量 0-超限参数界面 1-校准值参数界面
int Seg_Set_Arr[2] = {2000,0};         //参数数组 [0]-超限参数 [1]-校准值变量
unsigned char ucRtc[3] = {13,03,05};   //时间参数数组 [0]-时 [1]-分 [2]-秒
bit Seg_DM3_Mode;                      //回显界面模式变量 0-频率回显界面 1-时间回显界面
unsigned int Max_Freq;                 //最大频率值变量
unsigned int Max_Freq_Time[3];         //最大频率发生时间数组//DAC相关变量
float V_OutPut;                        //输出电压变量//按键功能相关变量
int code Step_Arr[2] = {1000,100};     //单次加减大小数组 [0]-超限参数单次增加量/减小量 [1]-校准参数单次增加量/减小量
int code Max_Arr[2] = {9000,900};      //上限值数组 [0]-超限参数上限值 [1]-校准参数上限值
int code Min_Arr[2] = {1000,-900};     //下限值数组 [0]-超限参数下限值 [1]-校准参数下限值//LED指示灯功能相关变量
unsigned char Time_200ms;              //闪烁间隔计时变量
bit Led_Flag;                          //闪烁标志位/*按键处理函数*/
void Key_Proc()
{if(Key_Flag) return;Key_Flag = 1;Key_Val = Key_Read();Key_Down = Key_Val & (Key_Val ^ Key_Old);Key_Old = Key_Val;switch(Key_Down){case 4://“界面”按键
//			 /*分开写*/
//			if(++Seg_Disp_Mode == 1)  Seg_DM1_Mode = 0;   //默认显示超限参数子界面
//			if(Seg_Disp_Mode == 3)  Seg_DM3_Mode = 0;     //默认显示频率回显子界面
//			if(Seg_Disp_Mode == 4)  Seg_Disp_Mode = 0;    //退回到最初界面/*合在一起写*/if(++Seg_Disp_Mode == 4) Seg_DM1_Mode = Seg_DM3_Mode = Seg_Disp_Mode = 0;break;case 5://“选择”按键if(Seg_Disp_Mode == 1)Seg_DM1_Mode ^= 1;else if(Seg_Disp_Mode == 3)Seg_DM3_Mode ^= 1;break;case 8://“加”按键if(Seg_Disp_Mode == 1 ){Seg_Set_Arr[Seg_DM1_Mode] += Step_Arr[Seg_DM1_Mode];if(Seg_Set_Arr[Seg_DM1_Mode] >= Max_Arr[Seg_DM1_Mode])Seg_Set_Arr[Seg_DM1_Mode] = Max_Arr[Seg_DM1_Mode];}break;case 9://“减”按键if(Seg_Disp_Mode == 1 ){Seg_Set_Arr[Seg_DM1_Mode] -= Step_Arr[Seg_DM1_Mode];if(Seg_Set_Arr[Seg_DM1_Mode] < Min_Arr[Seg_DM1_Mode])Seg_Set_Arr[Seg_DM1_Mode] = Min_Arr[Seg_DM1_Mode];}break;}
}/*信息处理函数*/
void Seg_Proc()
{unsigned char i = 3;unsigned char j = 0;if(Seg_Flag) return;Seg_Flag = 1;/*更新时钟*/Read_Rtc(ucRtc);/*获取最大频率及其发生时间*/if(Max_Freq < Freq){Max_Freq = Freq;for(j = 0;j < 3;j ++)Max_Freq_Time[j] = ucRtc[j];}switch(Seg_Disp_Mode){case 0://频率界面Seg_Buf[0] = 12;//FSeg_Buf[1] = Seg_Buf[2] = 10;if(Freq >= 0){Seg_Buf[3] = Freq / 10000 % 10;Seg_Buf[4] = Freq / 1000 % 10;Seg_Buf[5] = Freq / 100 % 10;Seg_Buf[6] = Freq / 10 % 10;Seg_Buf[7] = Freq % 10;/*高位为0时熄灭*/while(Seg_Buf[i] == 0){Seg_Buf[i] = 10;if(++i == 7) break;}}else{Seg_Buf[3] = Seg_Buf[4] = Seg_Buf[5] = 10;//熄灭Seg_Buf[6] = Seg_Buf[7] = 16;//LL} break;case 1://参数界面Seg_Buf[0] = 14;//PSeg_Buf[1] = (unsigned char)Seg_DM1_Mode+1;Seg_Buf[2] = Seg_Buf[3] = 10;//		  if(Seg_DM1_Mode == 0)//超限参数界面
//			{
//				Seg_Buf[4] = Seg_Set_Arr[0] /1000 % 10;
//				Seg_Buf[5] = Seg_Set_Arr[0] /100 % 10;
//				Seg_Buf[6] = Seg_Set_Arr[0] /10 % 10;
//				Seg_Buf[7] = Seg_Set_Arr[0] % 10;
//			}
//			else//校准值参数界面
//			{
//				if(Seg_Set_Arr[1] != 0)
//				{
//					/*确定符号位*/
//					if(Seg_Set_Arr[1] < 0)
//						Seg_Buf[4] = 15;//-
//					else 
//						Seg_Buf[4] = 10;//熄灭
//					
//					
//					Seg_Buf[5] = abs(Seg_Set_Arr[1]) /100 % 10;
//				  Seg_Buf[6] = abs(Seg_Set_Arr[1]) /10 % 10;
//				  Seg_Buf[7] = abs(Seg_Set_Arr[1]) % 10;
//				}
//				else
//				{
//					Seg_Buf[5] = Seg_Buf[6] = 10;
//				  Seg_Buf[7] = 0;
//				}				
//			}Seg_Buf[4] = Seg_DM1_Mode?(10 + 5 * (Seg_Set_Arr[Seg_DM1_Mode] < 0)):abs(Seg_Set_Arr[Seg_DM1_Mode]) /1000 % 10;Seg_Buf[5] = abs(Seg_Set_Arr[Seg_DM1_Mode]) /100 % 10;Seg_Buf[6] = abs(Seg_Set_Arr[Seg_DM1_Mode]) /10 % 10;Seg_Buf[7] = abs(Seg_Set_Arr[Seg_DM1_Mode]) % 10;/*校准值为0时,只显示一位0*/if(Seg_Set_Arr[Seg_DM1_Mode] == 0)Seg_Buf[5] = Seg_Buf[6] = 10;break;case 2://时间界面for(j = 0;j < 3;j++){Seg_Buf[j * 3] = ucRtc[j] / 10;Seg_Buf[j * 3 + 1] = ucRtc[j] %10;}Seg_Buf[2] = Seg_Buf[5] = 15;//-break;case 3://回显界面Seg_Buf[0] = 13;//Hif(Seg_DM3_Mode == 0)//频率回显界面{Seg_Buf[1] = 12;//FSeg_Buf[2] = 10;Seg_Buf[3] = Max_Freq / 10000 % 10;Seg_Buf[4] = Max_Freq / 1000 % 10;Seg_Buf[5] = Max_Freq / 100 % 10;Seg_Buf[6] = Max_Freq / 10 % 10;Seg_Buf[7] = Max_Freq % 10;/*高位为0时熄灭*/while(Seg_Buf[i] == 0){Seg_Buf[i] = 10;if(++i == 7) break;}}else//时间回显界面{Seg_Buf[1] = 11;//Afor(j = 0;j < 3;j ++){Seg_Buf[2+2*j] =  Max_Freq_Time[j] / 10;Seg_Buf[2+2*j+1] =  Max_Freq_Time[j] % 10;}}break;}
}/*其他显示函数*/
void Led_Proc()
{/*DAC相关*/if(Freq < 0) V_OutPut = 0;else if(Freq >= 0 && Freq <= 500) V_OutPut = 1;else if(Freq >= Seg_Set_Arr[0]) V_OutPut = 5;else V_OutPut = 1 + (float)(5.0 - 1.0)/(Seg_Set_Arr[0] - 500) * (Freq - 500);Da_Write(V_OutPut * 51);/**LED相关**/ucLed[0] = Led_Flag & (!Seg_Disp_Mode);ucLed[1] = (Led_Flag & (V_OutPut == 5)) || (Freq < 0);
}/*定时器0初始化函数*/
void Timer0Init(void)		//1毫秒@12.000MHz
{AUXR &= 0x7F;		//定时器时钟12T模式TMOD &= 0xF0;		//设置定时器模式TMOD |= 0x05;		TL0 = 0;		//设置定时初值TH0 = 0;		//设置定时初值TF0 = 0;		//清除TF0标志TR0 = 1;		//定时器0开始计时
}/*定时器1初始化函数*/
void Timer1Init(void)		//1毫秒@12.000MHz
{AUXR &= 0xBF;		//定时器时钟12T模式TMOD &= 0x0F;		//设置定时器模式TL1 = 0x18;		//设置定时初值TH1 = 0xFC;		//设置定时初值TF1 = 0;		//清除TF1标志TR1 = 1;		//定时器1开始计时ET1 = 1;EA = 1;
}/*定时器1中断服务函数*/
void Timer1_Isr(void) interrupt 3
{/*数码管90ms的减速*/if(++Slow_Down == 90){Seg_Flag = Slow_Down = 0;}/*按键10ms的减速*/if(Slow_Down % 10 == 0){Key_Flag = 0;}/*1s的计数*/if(++Time_1s == 1000){Time_1s = 0;Freq = TH0 << 8 | TL0;   //计算频率Freq += Seg_Set_Arr[1];  //加上校准值TH0 = 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闪烁200ms计时*/if(++Time_200ms == 200){Time_200ms = 0;Led_Flag ^= 1;}
}/*主函数*/
void main()
{Sys_Init();Timer0Init();Timer1Init();Set_Rtc(ucRtc);while(1){Key_Proc();Seg_Proc();Led_Proc();}
}

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;
}

Key.c

#include "Key.h"unsigned char Key_Read()
{unsigned char temp=0;P44 = 0; P42 = 1; P35 = 1; P34 = 1;if(P33 == 0) temp = 4;if(P32 == 0) temp = 5;if(P31 == 0) temp = 6;if(P30 == 0) temp = 7;P44 = 1; P42 = 0; P35 = 1; P34 = 1;if(P33 == 0) temp = 8;if(P32 == 0) temp = 9;if(P31 == 0) temp = 10;if(P30 == 0) temp = 11;P44 = 1; P42 = 1; P35 = 0; P34 = 1;if(P33 == 0) temp = 12;if(P32 == 0) temp = 13;if(P31 == 0) temp = 14;if(P30 == 0) temp = 15;/*P34引脚和NE555冲突*/
//	P44 = 1; P42 = 1; P35 = 1; P34 = 0;
//	if(P33 == 0) temp = 16;
//	if(P32 == 0) temp = 17;
//	if(P31 == 0) temp = 18;
//	if(P30 == 0) temp = 19;return temp;
}

Led.c

#include "Led.h"void Led_Disp(unsigned char addr,enable)
{unsigned char temp = 0x00;unsigned char temp_old = 0xff;if(enable)temp |= 0x01 << addr;elsetemp &= ~(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_wela[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
code unsigned char Seg_dula[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0x88,0x8e,0x89,0x8c,0xBF,0xC7};//0-9,10-熄灭,11-A,12-F,13-H,14-P,15--,16-Lvoid 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;
}

iic.c

#include "iic.h"
#include "intrins.h"
#define DELAY_TIME	10sbit 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();
}

ds1302.c

#include "ds1302.h"
#include "intrins.h"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 Set_Rtc(unsigned char *ucRtc)
{unsigned char i;Write_Ds1302_Byte(0x8e,0x00);for(i = 0;i < 3; i++)Write_Ds1302_Byte(0x84 - 2 * i, ucRtc[i] / 10 % 10 << 4 | ucRtc[i] % 10);Write_Ds1302_Byte(0x8e,0x80);
}void Read_Rtc(unsigned char *ucRtc)
{unsigned char i;unsigned temp;for(i = 0; i < 3; i++){temp = Read_Ds1302_Byte(0x85 - 2 * i);ucRtc[i] = temp /16 * 10 + temp % 16;}
}

结语

这套题整理也花了不少时间,但在整理的同时也让我对这套题的解法和思路有了更清晰的认知,收获还是蛮大的。
感谢你能看到这里,希望这篇笔记不仅对我有所帮助,也能对你能有所启发。
那么,文章里面有问题的话,也感谢大家指出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/32561.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

重邮数字信号处理-实验六用 MATLAB 设计 IIR 数字滤波器

一、实验目的 1、加深对 IIR 数字滤波器设计方法和设计步骤的理解&#xff1b; 2、掌握用模拟滤波器原型设计 IIR 数字滤波器的方法&#xff1b; 3、能编写 MATLAB 函数&#xff0c;掌握设计 IIR 数字滤波器的函数调用方法&#xff1b; 4、根据不同的应用场景&#xff0…

Linux中的基本指令(下)

目录 mv指令 more指令 less指令 head指令 tail 指令 继续理解文件 重定向和追加重定向操作 理解管道 find指令 whereis 指令 bc指令 uname ‒r指令 grep 指令 关机 扩展命令 zip/unzip 指令 tar指令 关于rzsz 系统间的文件互传 接上&#xff01; mv指令 m…

Python文件,模块

一.文件 1.生成一个文件: 2. 提示 : 第二次读时因为之前已经对文件进行了读取操作&#xff0c;文件指针可能已经移动到了文件末尾。在这种情况下&#xff0c;再次调用 read() 方法将不会读取到任何新的内容&#xff0c;因为已经没有未读取的数据了。可以使用 seek() 方法将文…

基于python的升级队列加速决策

a-f大等级是3级 a-c建筑每升1级分别需要8天 d-f建筑每升1级分别需要10天 目前以下建筑队列正在从0级升至1级 建筑A升级需要7天05&#xff1a;16&#xff1a;20 建筑b升级需要06&#xff1a;06&#xff1a;54 建筑c升级需要00&#xff1a;37&#xff1a;00 建筑d升级需要…

编译OpenSSL

OpenSSL简介 OpenSSL是一个用于加密和安全连接的开源软件库。它提供了一系列的加密算法、密码学功能和安全协议的实现&#xff0c;包括SSL&#xff08;Secure Sockets Layer&#xff09;和TLS&#xff08;Transport Layer Security&#xff09;等用于网络安全的协议。OpenSSL可…

Win 转 MacBook Pro 踩坑指南

前言 Window 和 macOS 系统的差异还是很大的&#xff0c;我从 Thinkpad 转用 M1 的 Macbook pro 已经一年了&#xff0c;几乎没有任何不适应&#xff0c;整体感受那是真的牛&#x1f443;&#xff0c;速度和续航惊艳到我了&#xff0c;同时开启 6个 vscode 加几十个浏览器标签…

uniapp uniCloud引发的血案(switchTab: Missing required args: “url“)!!!!!!!!!!

此文章懒得排版了&#xff0c;为了找出这个bug, 星期六的晚上我从9点查到0点多&#xff0c;此时我心中一万个草泥马在崩腾&#xff0c;超级想骂人&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; uniCloud 不想…

数据结构和算法--仅仅用于理解里面的术语,入门级别

数据结构和算法 预先知识&#xff1a;java 黑马前29节 cmd命令&#xff1a; 文件夹路径不区分大小写 E: dir:查看所有文件 cd 目录 :进入 cd… 返回上一级 cd 目录1\目录2 cd\ 回到根目录 cls 清屏 exit 退出 打开文件夹必须用cd 查找&#xff0c;但是文件不用&am…

【设计模式】通过访问者模式实现分离算法与对象结构

概述 定义&#xff1a;封装一些作用于某种数据结构中的各元素的操作(将数据结构于元素进行分离)&#xff0c;它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。 结构 访问者模式包含以下主要角色: 抽象访问者&#xff08;Visitor&#xff09;角色&#xff…

低版本 Linux 系统通过二进制方式升级部署高版本 Docker

​ 一、背景&#xff1a; 在一些 Linux 系统中&#xff0c;由于系统自带的软件源版本较低&#xff0c;或者因网络、权限等限制无法直接通过源文件来升级到最新版本的 Docker。这种情况下&#xff0c;采用二进制方式升级部署高版本 Docker 就成为一种有效的解决方案。下面将详…

SpringAI+Ollama+DeepSeek本地大模型调用

前言 大型语言模型&#xff08;LLM&#xff09;在自然语言处理领域取得了突破性进展&#xff0c;但其庞大的计算资源需求和高昂的调用成本&#xff0c;使得许多开发者望而却步。如何高效、便捷地调用大模型&#xff0c;并将其应用于实际场景&#xff0c;成为了亟待解决的问题。…

【大模型科普】AIGC技术发展与应用实践(一文读懂AIGC)

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈人工智能与大模型应用 ⌋ ⌋ ⌋ 人工智能&#xff08;AI&#xff09;通过算法模拟人类智能&#xff0c;利用机器学习、深度学习等技术驱动医疗、金融等领域的智能化。大模型是千亿参数的深度神经网络&#xff08;如ChatGPT&…

数据结构与算法:归并排序

目录 归并排序的基本思想 归并排序的特性总结 代码 归并排序的非递归版 归并排序的基本思想 归并排序是建立在归并操作上的一种有效的排序算法。改算法是采用分治法的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使每个子序列…

阿里云操作系统控制台评测:国产AI+运维 一站式运维管理平台

阿里云操作系统控制台评测&#xff1a;国产AI运维 一站式运维管理平台 引言 随着云计算技术的飞速发展&#xff0c;企业在云端的运维管理面临更高的要求。阿里云操作系统控制台作为一款集运维管理、智能助手和系统诊断等多功能于一体的工具&#xff0c;正逐步成为企业高效管理…

爬虫案例十三js逆向模拟登录中大网校

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、网站分析二、代码 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; js 逆向模拟登录中大网校 提示&#xff1a;以下是本篇文章正文内…

sql靶场--布尔盲注(第八关)保姆级教程

目录 布尔盲注&#xff08;第八关&#xff09; 1.判断 2.确认布尔盲注 3.手工尝试布尔盲注 表名字符 表数 表名长度 表字符 字段数 字段名长度 字段字符 4.脚本布尔盲注注入 布尔盲注&#xff08;第八关&#xff09; 1.判断 布尔盲注了&#xff0c;这种页面只会有…

【C++入门】变量和基本类型

目录 一、 基本内置类型 1.1. 整型&#xff08;Integer Types&#xff09; 1.2. 浮点型&#xff08;Floating-point Types&#xff09; 1.3. 字符型&#xff08;Character Type&#xff09; 1.4. 布尔型&#xff08;Boolean Type&#xff09; 1.5. 示例代码 二、变量声明…

JVM内存结构笔记03-方法区

文章目录 方法区1.定义2.组成方法区与永久代和元空间的关系为什么要将永久代 (PermGen) 替换为元空间 (MetaSpace) 呢? 3.方法区常用参数4.运行时常量池常量池运行时常量池定义查看class文件 方法区 1.定义 方法区属于是 JVM 运行时数据区域的一块逻辑区域&#xff0c;是各个…

数据库语句

环境变量path下的目录是系统目录。 #include <iostream> #include <mysql.h> #pragma comment(lib,"libmysql.lib")//链接libmysql.dll动态库的中间桥 // MYSQL* conn;//数据库句柄。后面还有网络句柄&#xff08;用来网络收发数据&#xff09; bool co…

Word 小黑第15套

对应大猫16 修改样式集 导航 -查找 第一章标题不显示 再选中文字 点击标题一 修改标题格式 格式 -段落 -换行和分页 勾选与下段同页 添加脚注 &#xff08;脚注默认位于底部 &#xff09;在脚注插入文档属性&#xff1a; -插入 -文档部件 -域 类别选择文档信息&#xff0c;域…