新建工程,以I/O模式编写代码,在CT107D单片机综合训练平台上,实现以下功能:
1、将IIC总线的底层驱动代码文件正确移植到工程中。
2、将J5配置BTN模式,把S4、S5和S6设置为独立按键。
3、系统上电后,电压参数为3.00V,报警计数为0。单片机循环采样PCF8591芯片AIN3通道的输入电压,并将该电压与电压参数比较。采样电压小于电压参数时,启动报警计时,报警计数值每秒钟加1累计。报警持续超过2秒钟,L1点亮;超过4秒钟,L1和L2点亮,超过6秒钟,L1、L2和L3点亮,并且L8开始循环秒闪,即点亮1秒,熄灭1秒。直到采样电压大于等于电压参数,报警计时解除,报警计数清0,全部指示灯熄灭,秒闪停止。
3、通过数码管实现电压数据、参数设置和报警计数三个界面。系统上电后,默认工作在电压数据界面,如下图,电压数据为PCF8591芯片AIN3通道的实时电压。

在电压数据界面中按下S4按键,进入参数设置界面,如下图,仅在该界面中,S5和S6按键有效。按下S5按键,电压参数减小0.5V,减小到0.00V后,再次按下S5返回5.00V;按下S6按键,电压参数增加0.5V,增加到5.00V后,再次按下S6返回0.00V。

在参数设置界面中按下S4按键,进入报警计数界面,如下图,报警计数使用2位数码管,未用的位数熄灭,最大值为99,当到达99时,停止不再累计。

在报警计数界面中按下S4按键,重新返回电压数据界面,如此循环切换界面。
【小提示】:
IIC接口的基本原理,可见本博客:《【蓝桥杯单片机进阶强化-01】IIC总线接口技术基础》。
PCF8591的基本原理,可见本博客:《【蓝桥杯单片机进阶强化-02】PCF8591的基本原理与A/D转换应用》
/*==================蓝桥杯单片机特训==================
【进阶06】:基于PCF8591的DAC模拟电压输出
**平 台:CT107D单片机综合实训平台
**模 式:IO模式
**底层驱动文件:2022年竞赛资源数据包提供的文件
**设 计:欧浩源(小蜜蜂老师,ohy3686@qq.com)
**时 间:2022-04-05
**更多详见:www.xmf393.com
====================================================*/
#include "reg52.h"
#include "iic.h"
sbit S4 = P3^3;
sbit S5 = P3^2;
sbit S6 = P3^1;
//定义动态显示中单个数码管点亮时长
#define TSMG 500
//-------共阳数码管的段码编码表(无小数点)--------
//0 1 2 3 4 5 6 7 8 9 A B C D E F - .
unsigned char code SMG_NoDot[18]={0xc0,0xf9,
0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f};
//-------共阳数码管的段码编码表(带小数点)--------
//0. 1. 2. 3. 4. 5. 6. 7. 8. 9.
unsigned char code SMG_Dot[10]={0x40,0x79,
0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
//-----------------------------------------------
unsigned int adc_value = 0; //AIN3的采样数据
float adc_volt = 0; //AIN3的换算电压
unsigned int smg_volt = 0; //AIN3的显示电压
unsigned int param = 300; //电压参数,3.00V
unsigned char stat_smg = 1; //当前显示界面标志
unsigned char num = 0; //报警计数变量
unsigned int count_t = 0;
unsigned char stat_led = 0xff; //LED灯控制状态
unsigned char F_shan = 0; //启动秒闪灯标志
unsigned char F_time = 0; //启动报警计时标志
/*====锁存器设置和数码管显示的代码参考前面的案例====*/
//=================系统信息数码管显示=================
void DisplaySMG_Info()
{
switch(stat_smg)
{
//电压数据界面
case 1:
DisplaySMG_Bit(7,SMG_NoDot[smg_volt % 10]);
DisplaySMG_Bit(6,SMG_NoDot[(smg_volt / 10) % 10]);
DisplaySMG_Bit(5,SMG_Dot[smg_volt / 100]);
//提示符:U---->0xC1
DisplaySMG_Bit(0,0xc1);
break;
//参数设置界面
case 2:
DisplaySMG_Bit(7,SMG_NoDot[param % 10]);
DisplaySMG_Bit(6,SMG_NoDot[(param / 10) % 10]);
DisplaySMG_Bit(5,SMG_Dot[param / 100]);
//提示符:P---->0x8C
DisplaySMG_Bit(0,0x8c);
break;
//报警计数界面
case 3:
DisplaySMG_Bit(7,SMG_NoDot[num % 10]);
if(num / 10 != 0)
{
DisplaySMG_Bit(6,SMG_NoDot[num / 10]);
}
//提示符:S---->0x92
DisplaySMG_Bit(0,0x92);
break;
}
}
//===================定时器T0初始化===================
void Init_Timer0()
{
//定时器计数初值设置:50ms
TH0 = (0 - 50000) / 256;
TL0 = (0 - 50000) % 256;
TMOD = 0x01; //T0的定时模式1:16位不可重装模式
ET0 = 1; //使能定时器0中断
EA = 1; //打开总中断
TR0 = 1; //启动定时器0
}
//===============定时器T0的中断服务函数================
void Service_Timer0() interrupt 1
{
TH0 = (0 - 50000) / 256;
TL0 = (0 - 50000) % 256;
if(F_time == 1) //启动报警计时
{
count_t++; //50ms单位定时累计
if(count_t % 20 == 0) //1秒时长
{
if(num != 99) //没有到达最大值99前
{
num++; //报警计数累计
}
if(F_shan == 1) //启动秒闪功能
{
if((stat_led & 0x80) == 0x80)
{
stat_led &= ~0x80; //点亮L8灯
}
else
{
stat_led |= 0x80; //熄灭L8灯
}
}
}
if(count_t > 120) //超过6秒
{
stat_led &= ~0x07; //点亮L1 L2 L3
F_shan = 1;
}
else if(count_t > 80) //超过4秒
{
stat_led &= ~0x03; //点亮L1 L2
}
else if(count_t > 40) //超过2秒
{
stat_led &= ~0x01; //点亮L1
}
else
{
stat_led = 0xff;
}
}
}
//===============PCF8591电压采样处理函数===============
unsigned char Read_PCF8591_AIN3()
{
unsigned char tmp;
IIC_Start();
IIC_SendByte(0x90); //PCF8591的写设备地址
IIC_WaitAck();
//选择AD转换通道
IIC_SendByte(0x03); //AIN3通道,可调电阻电压
IIC_WaitAck();
IIC_Stop();
DisplaySMG_Info(); //等待电压转换完成
IIC_Start();
IIC_SendByte(0x91); //PCF8591的读设备地址
IIC_WaitAck();
//读出AD采样数据
tmp = IIC_RecByte();
IIC_SendAck(1); //产生非应答信号
IIC_Stop();
return tmp;
}
//=================电压数据应用分析处理=================
void App_Volt()
{
unsigned char i;
//采样通道3的电压,并做简单的均值滤波处理
adc_value = 0;
for(i = 0; i < 3; i++)
{
adc_value += Read_PCF8591_AIN3();
}
adc_value = adc_value / 3;
//将ADC采样到的数据换算成对应的电压值
adc_volt = adc_value * (5.0 / 255);
smg_volt = adc_volt * 100;
//当前电压与电压参数的比较处理
if(smg_volt < param) //当前电压 < 电压参数
{
if(F_time == 0)
{
F_time = 1; //标志计算持续时间
}
}
else //当前电压 >= 电压参数
{
F_time = 0; //恢复待计时状态
F_shan = 0;
count_t = 0; //计时变量清0
num = 0;
stat_led |= 0xff; //指示灯L1熄灭
}
DisplaySMG_Info(); //动态刷新数码管
Set_HC573(4, stat_led); //更新LED灯控制状态
}
//===================按键扫描处理函数==================
void Scan_Keys()
{
if(S4 == 0) //切换界面
{
DelaySMG(500);
if(S4 == 0)
{
if(stat_smg == 1)
{
stat_smg = 2; //切换至:参数设置
}
else if(stat_smg == 2)
{
stat_smg = 3; //切换至:报警计数
}
else if(stat_smg == 3)
{
stat_smg = 1; //切换至:电压数据
}
while(S4 == 0) //松手检测
{
DisplaySMG_Info(); //保持数码管动态显示
}
}
}
if(S5 == 0) //电压参数减小
{
DelaySMG(500);
if(S5 == 0)
{
if(stat_smg == 2) //仅在参数设置中有效
{
if(param != 0) //未减小到最小值
{
param = param - 50; //每按1下,减小0.5V
}
else
{
param = 500; //边界处理
}
}
while(S5 == 0)
{
DisplaySMG_Info();
}
}
}
if(S6 == 0) //电压参数增加
{
DelaySMG(500);
if(S6 == 0)
{
if(stat_smg == 2) //仅在参数设置中有效
{
if(param != 500) //未增加到最大值
{
param = param + 50; //每按1下,增加0.5V
}
else
{
param = 0; //边界处理
}
}
while(S6 == 0)
{
DisplaySMG_Info();
}
}
}
}
【注】:更多关于蓝桥杯单片机备赛内容,详见《蓝桥杯单片机设计与开发》小蜜蜂特训手册,本站可下载,相关更多蓝桥杯的案例完整源码及学习备赛笔记,欢迎进入 “小蜜蜂笔记” 公众号。
说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时
目录前言: 一、ASC分析代码实现二、 卡片分析代码实现三、 直线分析代码实现四、货物摆放分析代码实现小结:前言: 在刷题的过程中,发现蓝桥杯的题目和力扣的差别很大。让人有一种不一样的感觉,蓝桥杯题目偏向对于实际问题用编程去的解决,而力扣给人感觉很锻炼自己的编程思维,逻辑能力。两者结合去刷,相信会有不一样的收获。 一、ASC 已知大写字母A的ASCII码为65,请问大写字母L的ASCII码是多少?分析 这道题目看上去很简单,我们需确定自己计算的准确,所以我建议用编程去解决。代码实现publicclassTest8{publicstaticvoidmain(String[]args){Sy
目录一、inout在设计文件中的使用方法1.1、inout的第一种使用方法1.2、inout实现的第二种使用方法1.3、inout使用总结 二、inout在仿真测试中的使用方法一、inout在设计文件中的使用方法在FPGA的设计过程中,有时候会遇到双向信号(既能作为输出,也能作为输入的信号叫双向信号)。比如,IIC总线中的SDA信号就是一个双向信号,QSPIFlash的四线操作的时候四根信号线均为双向信号。在Verilog中用关键字inout定义双向信号,这里总结一下双向信号的处理方法。1.1、inout的第一种使用方法 实际上,双向信号的本质是由一个三态门组成的,三态门可以输出高电平,低电
我想从gtk3中的Widget发出自定义信号。在GTK2中,有一个名为signal_new的函数来创建一个新信号。您可以在此处查看示例:https://github.com/ruby-gnome2/ruby-gnome2/blob/ec373f87e672dbeeaa157f9148d18b34713bb90e/glib2/sample/type-register.rb在GTK3中,这个功能似乎不再可用。那么在ruby的GTK3中创建自定义信号的新方法是什么? 最佳答案 GTK3更改为使用define_signal方法而不是si
我想知道如何连接到带参数的信号(使用Rubyblock)。我知道如何连接到一个不带参数的:myCheckbox.connect(SIGNAL:clicked){doStuff}但是,这不起作用:myCheckbox.connect(SIGNAL:toggle){doStuff}它不起作用,因为切换槽采用参数voidQAbstractButton::toggled(boolchecked)。我怎样才能让它与参数一起工作?谢谢。 最佳答案 对您的问题的简短回答是,您必须使用slots方法声明要连接的插槽的方法签名:classMainGU
我有在服务器上运行的代码,在服务器硬关闭之前,发送了一个信号SIGTERM让我的代码知道它需要清理。我想在发生这种情况时运行代码并将信号发送回同一个程序,以便任何其他需要清理的代码都可以这样做。我不想捕获信号或改变信号行为,我只需要在我的程序的其余部分解释SIGTERM之前运行一些东西。目前我可以做类似的事情Signal.trap('TERM')doputs"Gracefulshutdown"exitend但如果同一个应用中的多段代码试图做同样的事情,它就不起作用了。例如:Signal.trap('TERM')doputs"Gracefulshutdown"exitendSignal.
?作者主页:静Yu?简介:CSDN全栈优质创作者、华为云享专家、阿里云社区博客专家,前端知识交流社区创建者?社区地址:前端知识交流社区?博主的个人博客:静Yu的个人博客?博主的个人笔记本:前端面试题个人笔记本只记录前端领域的面试题目,项目总结,面试技巧等等。接下来会更新蓝桥杯官方系统基础练习的VIP试题,依然包括解题思路,源代码等等。问题描述:给定当前的时间,请用英文的读法将它读出来。时间用时h和分m表示,在英文的读法中,读一个时间的方法是: 如果m为0,则将时读出来,然后加上“o’clock”,如3:00读作“threeo’clock”。 如果m不为0,则将时读出来,然后将分读出来,如5
本人是音乐爱好者,从小就特别喜欢那个随着音乐跳动的方框效果,就是这个:arduino上一大把对,我忍你很久了,我就想用mpy做,全网没有,行我自己研究。果然兴趣是最好的老师,我之前有篇博客专门讲音频,有兴趣的可以回顾一下。提到可视化频谱,必然绕不开fft,大学学过这玩意,当时一心玩,老师讲的一个字都么听进去,网上教程简略扫了一下,大该就是把时域转频域的工具,我大mpy居然没有fft函数,奶奶的,先放着。音频信息如何收集?第一种傻瓜式的ADC,模拟转数字,原始粗暴,第二种,I2S库,我之前博客有讲过,数据是PCM编码。然后又去学PCM编码,一学豁然开朗,舒服,以代码为例:audio_in=I2S
十四届蓝桥青少组模拟赛Python-20221108T1.二进制位数十进制整数2在十进制中是1位数,在二进制中对应10,是2位数。十进制整数22在十进制中是2位数,在二进制中对应10110,是5位数。请问十进制整数2022在二进制中是几位数?print(len(bin(2022))-2)#运行结果:11T2.晨跑小蓝每周六、周日都晨跑,每月的1、11、21、31日也晨跑。其它时间不晨跑。已知2022年1月1日是周六,请问小蓝整个2022年晨跑多少天?#样例代码1ls=[0,31,28,31,30,31,30,31,31,30,31,30,31]ans=0k=6foriinrange(1,13)
本文代码使用HAL库。文章目录前言一、MCP4017的重要特性二、MCP4017计算RBW阻值三、MCP4017地址四、MCP4017读写函数五、CubeMX创建工程(利用ADC测量MCP4017电压)、对应代码:总结前言一、MCP4017的重要特性蓝桥杯板子上的是MCP4017T-104ELT,如图1。MCP4017是一个可编程电阻,通过写入的数值可以改变电阻的大小。重点在于6引脚(W),5引脚(B