8051U深度入门打卡学习记录
第一集 序言
视频聚焦于8051U单片机,介绍了8051U相较于STC32G的显著功能提升,包括优化的QSPI flash芯片读写功能,全功能的iPhone录放音,PWMDMA功能的改进,以及硬件浮点存储单元支持的频谱分析仪和手写计算器演示。
还展示了8051单片机在实现屏幕显示和录放音功能方面的应用。显示屏可以刷新各种界面,包括汉字、英文、图片和旋转显示,显示效果良好,适用于图形菜单等。其次,通过烧录特定的程序,实现了触控校准功能,能够显示校准小圆点并提供校准参数。此外,还演示了数字录放音功能,通过修改代码和连接外置喇叭,可以实现停止、录音、放音及音量调节等操作。8051U单片机在实现复杂功能方面的强大能力。
讨论了PWMDMA功能及其在不同项目中的应用,包括在8WS2812点阵屏上实现的时钟显示、频谱分析仪的开发,以及一个手写计算器程序。特别强调了使用PWM加DMA技术可以直接驱动大量2812灯进行显示,而无需任何干扰,展现了该技术的强大功能。此外,还提及了通过FFT技术快速分析频率的能力,以及一个开源的手写计算器程序,
第二集 开发板实验箱介绍以及下载说明
1、
实验箱的正面功能包括USB Type A口用于程序烧录,USB link ED接口作为下载烧录调试工具,USB Type C接口提供另一种数据线连接选项,以及板子背面的USB转双串口芯片,支持高达10兆的波特率,适用于串口实验。
实验箱包含TF卡插座、示波器输入、放音输出、话筒录音等功能,并支持OLED屏和流水灯等组件,适合初学者入门和进阶使用。
AI8051主控芯片,包含48个引脚。
QSPI flash芯片用于存储数据,如动画图片,以及LCD对比度调节和RTC电池确保断电后时钟仍能准确计时。
电子板子背面的关键元器件,包括无源晶振、24C02存储芯片、DS18B20温度传感器、无源蜂鸣器、SP3485通信芯片以及USB转换芯片AI8H2K12U。无源晶振是RTC功能实现的必要条件,24C02芯片用于保存关键数据,DS18B20提供低成本高精度温度检测,而USB转换芯片则支持与电脑的通信.
2、
实现单片机实验箱功能所需的软件配置步骤。
访问STC官网下载所需软件和芯片规格书
深圳国芯人工智能有限公司-产品_AI8051U系列
深圳国芯人工智能有限公司-库函数
深圳国芯人工智能有限公司-工具软件
深圳国芯人工智能有限公司-实验箱
第三集 点亮第一颗LED
一、创建和配置单片机工程项目
如何在8051U开发环境中创建一个新的工程项目。
创建空工程的三个步骤:创建空工程、添加头文件、输入代码及编译。
按照手册默认配置进行设置。选择模式和项目大小,根据需要配置项目设置,如代码大小和输出选项。正确使用系统路径下的头文件和项目文件夹内的自定义文件
二、单片机程序中的循环与一次性执行
单片机程序中主函数的执行逻辑,区分一次性执行代码与循环执行代码的区别。
三、点亮LED灯的编程过程与问题解决
编程中语句以分号结束的规则,以及代码编写、编译、下载到单片机并最终点亮LED灯的全过程。过程中遇到编译、下载、硬件连接等问题,通过检查文件、重新编译和确保硬件正确连接得以解决,最终成功点亮LED灯。
GPIO的概念,即它可以作为输入或输出使用,其配置包括准双向口、推挽输出和高阻输入等模式。
如何通过设置PNM0和PNM1寄存器来配置单片机的IO口,
如何通过写入特定的二进制或十六进制数值到相关的寄存器,来控制IO口输出低电平,以实现点亮LED等操作
初始化P0和P4端口为准双向口,以便能够执行输入输出功能。通过设置P0M0和P0M1寄存器,将P0端口的8个IO设置为双向口,同理对P4端口进行设置。为了点亮LED,需在P40输出低电平以打开开关,并在P00或P01端口输出低电平以点亮相应的LED灯。通过调整代码,可以实现点亮不同组合的LED灯。最后,通过下载更新代码至单片机,验证LED灯的点亮情况。
加油加油 第四集 USB不停电下载
介绍一种快速方法,能够在编译程序后自动进行下载,无需手动按下特定按钮。通过演示,可以看到在初次下载时需要手动操作,但后续只需点击下载按钮,系统会自动跳转到USB下载模式,实现程序的自动下载。
如何获取和下载用于实现USB不停电下载的文件?
需要访问STC官网(stcar.com)下载相关的软件工具库函数中的USB库文件。在官网上直接输入网址连接,找到并下载对应8系列或32G系列硬件USB芯片的CDC库文件,将其保存至指定文件夹待后续使用。
深圳国芯人工智能有限公司-库函数
如何正确选择并移植库文件到项目中?
在解压下载好的库文件后,根据之前选择的8位或32位微控制器,选择相应的CDC库文件移植到项目中。在实际操作中,需注意识别不同文件类型(如.lib和.h头文件),并将其复制至新建的“示例代码”文件夹下,以便后续移植和编译。
上一节课遗留的代码如何与新功能整合?
在本节课的基础上,将把上一节课的LED点亮程序代码与新的USB不停电下载功能相结合。首先,会将上节课的有用代码复制到新的工程文件中,并确保移植的代码能够成功编译。在移植过程中,需要添加重要的头文件以支持新功能的实现。
中断和查询如何区分?
中断的特点是无论代码执行到哪一行,都会立即响应并执行。而查询则会在一整圈代码执行完毕后(如大括号内的循环结束后)才开始运行。具体到示例中,USB CDC的代码会在每次大括号执行结束或运行到特定行时才执行。
为了代码稳定高效运行,通常选择哪种方式?如何将USB CDC库文件和头文件添加到工程中?
为了保证代码的稳定高效运行,一般选择查询方式。例如,在示例代码中,就采用了查询模式,并从库文件中复制了相应的32位STCCDC库文件和头文件到示例代码所在路径下。首先找到USB CDC的点lib文件和对应的头文件(例如04文件),复制到示例代码所在的慢点C路径下。然后通过工程管理器添加这些文件,只需添加一个点lib文件,因为一个点C加一个点H可以生成一个点lib文件,这种方式能够防止源码被篡改并方便快速移植。
如何在工程中初始化USB函数且保证其安全性?
在工程中初始化USB函数时,由于源码文件不可见,可以通过全局搜索功能查找USB函数的声明和调用位置,确认其所在头文件后直接复制并粘贴到工程中。这样可以确保文件的安全性和移植便捷性,同时对于不熟悉的文件结构,直接复制现有代码更为高效。
在初始化USB时,如何设置端口为准双向口?
在USB初始化函数中,可以将所有P0至P7端口设置为准双向口,这样可以减少后续代码的工作量。在初始化函数中直接复制并使用相应的设置命令即可。
如何处理命令参数及确保其与目标单片机兼容?
复制并粘贴命令参数代码至目标工程中,并根据实际使用的单片机型号调整头文件和库文件(如从STC32G头文件改为8051U头文件)。此外,注意一些特定字段如STCRSP的配置,确保下载程序前单片机接收到的密码与之匹配,以避免出现下载错误。
如何理解P_SW2寄存器中的EAXFR字段以及其对XFR寄存器的影响?
EAXFR字段是P_SW2寄存器的一部分,它控制对EAX3FR寄存器的访问权限。当EAXFR为0时,禁止访问XFR寄存器;当为1时,则允许访问。由于USB相关寄存器位于XFR列表中,因此需要将EAXFR设置为1以确保能够访问这些寄存器。
如何在二进制数中精确设置或修改特定位(如B7位)的值?
要精确设置或修改B7位的值,可以采用或等于运算。例如,若想将B7位置为1,而不影响其他位,可以使用符号“|”进行或运算,如“0X80 | value”,其中value是其他位的二进制数。这样,原值的低七位不变,而最高位会被置为1。
在配置寄存器时,如何决定是否启用XFR寄存器?
通过检查P_SW2寄存器中的EAXFR字段来判断是否启用XFR寄存器。当EAXFR字段的第七位为0时,禁止访问;若为1,则可以有效访问。由于USB的一些寄存器在XFR列表中,为了能访问这些寄存器,必须确保XFR寄存器打开,因此我们需要将EAXFR设置为1。
在编程中如何实现“或”和“与等于”操作?
发言人:在编程中,“或”操作用符号“|”表示,它会根据位上的值决定最终结果,只要有一个位置为1,该位置的结果就会是1。而“与等于”操作通常不直接使用符号表示,但可以通过先进行“与”操作再赋值来实现,即先用“&”符号进行与运算,然后将结果赋值给目标变量。
在寄存器中,为什么需要将USB允许中断的位设置为1?
因为要使用USB的不停电下载功能,必须确保USB中断被打开。在寄存器中,通过检查并设置相应位(例如IE2中的B7位)为1,可以实现对USB中断的控制。
总中断是如何理解的?
总中断是一个类似总开关的控制位,它决定了所有中断是否可以被激活。在中断系统中,所有中断请求都需要通过一个名为EA的开关连接到后续处理部分。因此,要启用任何中断功能,必须首先确保EA这个总开关处于开启状态。
在代码中,“等待USB完成配置”这一行的作用是什么?
发言人:这行代码用于确保在进行其他操作之前,USB已经完成初始化和配置过程。通过这种方式,可以确保USB处于可用状态,从而实现数据的正常传输和接收。
如何实现不停电下载功能,并在代码中体现这一功能?
在特定代码段中,当接收到特定数据时,会自动触发HID right操作,并将接收到的数据回发。这一系列代码结合USB初始化,就实现了不停电下载功能。
在编写代码时,如何处理未调用函数的警告(如L57警告)?
对于未调用函数的警告,可以在编译器中使用特定指令屏蔽掉不需要的函数声明,这样就可以避免编译错误。具体操作是在编译过程中输入相应的指令,确保最终生成的代码只包含被调用的函数。
第五集 C语言基础
为什么在课程中要重点讲解C语言USB CDC串口至printf函数的实现?printf函数在C语言中的原型及使用说明是什么?
printf函数能快速打印变量类型等信息,对于C语言开发非常实用,尤其在单片机编程中,它可以帮助开发者高效地调试和开发。在工程中,printf函数实际上是重定向到gap print FHID里的。其原型中的FMT是一个格式控制字符串,包含普通字符和转换说明。普通字符输出时保持原样,而转换说明会替换为特定字符或字符串,如"%s"代表一个字符串。
如何在单片机上使用printf函数?如何在代码中正确使用printf函数并展示其效果?
在USB库中打开PRINTF_HID宏定义即可直接使用。具体操作是在代码中找到相关位置,去掉反斜杠即可打开此功能。可以在接收数据的地方添加printf函数,例如接收数据后打印一串英文字符串"STC YYDS",并使用"\n"实现换行。通过编译、下载并运行程序,可在实际硬件环境中观察到打印结果。
如何解决使用printf函数时出现的不停电下载不成功问题?
出现此问题可能是因为选择了错误的文件或未添加liba文件。确保正确配置并时常检查文件是否存在误删情况。
在串口通信中,如何控制是否显示发送的数据?
在串口通信时,若想隐藏发送的数据,可以在更多设置中取消勾选“显示发送的数据”,然后点击确定保存设置。之后再次发送数据时,只有接收的数据才会显示在界面上。
如何正确使用printf函数中的格式化字符串,并解释“%”的作用?
在printf函数中,格式化字符串中的“百分之S”是一个特殊标签,它会根据后面的参数以字符串形式进行替换。例如,如果有三个百分号(即N个转),则需要N+1个参数来替换。其中,“%”可以是变量或常量,并且必须放在英文双引号内,而附加参数则位于双引号之外并用逗号分隔。
在printf函数中,“%d”和“%ld”分别代表什么输出形式?
“%d”表示以十进制整数的形式输出一个数字,而“%ld”对应长整型,用于输出更长的整数值。在C语言中,整型和长整型的区别在于他们能表示的最大数值范围不同,但可以通过printf函数中的格式化字符串来指定具体输出形式。
在单片机或串口助手环境下,制表符、换行符等特殊字符是如何表示的?
在该环境下,水平制表符通常表现为四个空格(\t),回车符通常显示为一个回车符号(即\n)。换行符则表现为一个换行标志。需要注意的是,不同软件或设备可能对这些特殊字符有不同的处理方式,但在编程实践中,直接使用如“\t”、“\n”这样的转义序列通常是安全且正确的。
在文本模式和十六进制模式下,printf函数显示数据有何不同?
在文本模式下,printf函数会显示按照ASCII码表对应字符形式的内容;而在十六进制模式下,它会显示每个字符对应的16进制数。例如,大写字母"S"在十进制数中是83,在十六进制数中是53。根据实际需求选择合适的显示模式有助于调试和理解数据的真正内容。
如何将其他进制数转换为十进制数?
要将不同进制数转换为十进制数,首先需要理解每个数字位所代表的数值是按照该进制的基础进行幂次方计算的。例如,对于二进制数,最低位代表2^0,次高位代表2^1,中间零代表2^2,最前面的数字则代表2^3。通过将各个位置上的数字乘以对应的基础的幂次方并求和,即可得到十进制数值。此外,也可以利用程序员计算器直接进行转换,只需记住十进制与16进制(或八进制、二进制)的对应关系即可。
如何在编程中使用64位变量并设定变量类型?
在32位编译器的程序中,若要使用64位变量,需在程序头部添加特定指令,如`#pragma float64`。这样可以在程序开始处声明64位变量。对于变量类型的选择,编译器提供了多种类型,如char(8位,范围0-255)、double(64位,可存储小数点后更多位数)。每个变量都有其固定的长度,如char类型只能存储0到255之间的值,而double类型可以存储较大范围内的数值,但在特定条件下可能会受到最大值或最小值的限制。
如何在C语言中定义变量及简化冗长的变量声明?
在C语言中定义变量时,需在变量类型后面跟上变量名称,且名称需遵循不重复和不使用系统关键词的原则。例如,可以定义名为XYZ或HIJKLMN的变量。若觉得每次定义变量过于繁琐,可以采用宏定义的方式简化表达,如通过#define u8 unsigned char来代替长串变量声明,后续只需使用U8即可代替原来的长串代码。
C语言中的运算符有哪些及其用法?
C语言中最常用的运算符包括加(+)、减(-)、乘(*)、除(/),其中除法运算的结果仅取整数部分。另外,还有一个特殊运算符%用于求余数,如X除以Y的余数用X % Y表示。此外,还有自增(++)和自减(--)运算符,它们分别使变量加1或减1,例如X++表示将X的值加1,Y--表示将Y的值减1。
在编程中如何定义变量的类型和使用范围?
在编程时,变量的类型在其所在的大括号定义域内有效,只能在这个大括号及其嵌套的大括号中使用。如果希望变量在全局范围内都能被调用,则需要将其定义在外部。
如何理解字符串中的百分号以及如何进行数值计算并显示结果?
在引号内的字符串中,百分号不会被当作转义符处理,因此可以直接显示。当需要将计算结果(如X除以Y)显示为字符串时,应确保该表达式在有逗号的地方替换为对应的数值,并且可以利用格式化字符串的方式输出,例如使用“%u”格式符显示无符号整数结果。
如何处理整数溢出问题及数据类型的强制转换?
为了应对可能的八位整数乘法或除法导致的溢出问题,可以将变量强制转换为16位无符号整数。通过写作类似"(int16_t)X / Y"这样的表达式,可确保计算结果不会超出八位整数范围,同时避免了溢出风险。
如何区分乘除号与取余号,并在编程中正确使用它们?
在编程中,可以通过符号区分乘除号(* 和 /)与取余号(%)。例如,20除以10时,若仅用除号,则结果为2;若使用取余号,则会得到余数0。当需要输出百分号时,需额外添加一个百分号以进行转义。
单片机中的真伪判断规则及其在条件语句中的应用是什么?
在单片机编程中,零被认为是假,非零数值(如1或100)视为真。关系运算符如等于、不等于、大于、小于、大于等于和小于等于可用于判断条件是否成立。这些判断结果通常在if-else语句中使用,其中if部分在条件为真时执行,而else部分在条件为假时执行。
逻辑运算符的运作原理是什么?如何通过例子理解逻辑运算的结果?
逻辑运算符的运作基于真与假的条件判断。例如,“与”运算符要求两边条件都为真时结果才为真,只要有一个为假则结果即为假。取反符号则是对单个条件进行逻辑非操作,真变假,假变真。在给出的例子中,当变量A和B都为非零数(即都为真)时,与运算的结果为真,表现为连续运行无换行符导致输出未换行。若将其中一个变量改为零,则整个表达式变为假,输出结果会自动换行。这说明了“与”运算需要两边条件同时为真才输出真。
赋值运算符在编程中的使用方法是怎样的?
赋值运算符在编程中主要用于将某个表达式的结果赋给指定变量。例如,C = A + B 表示将A与B相加的结果赋给C。此外,还有加等于、减等于、乘等于、除等于等运算符,分别用于完成相应的算术操作并将结果赋值回原变量。
如何理解和运用逻辑运算中的“”(异或)和“或”运算?
异或运算的特点是相同出零,不同出一;而“或”运算则是只要对应位有一个为一,结果就为一。可以通过实际的二进制数运算来理解和掌握这两个逻辑运算符的逻辑特性。
左移和右移运算符的作用是什么?
左移运算符是将二进制数的每一位向左移动指定的位置,相当于在末尾添加相应数量的零;右移运算符则是将二进制数的每一位向右移动指定的位置,相当于去掉最左边的几位。这两个运算符主要用于处理二进制数据的位操作.
在编程中如何避免变量类型溢出问题?
在编程时要特别注意变量类型及其数值长度,以防止发生溢出,即变量存储的数值超过其最大范围。一旦发生溢出,将无法恢复原始数值。因此,应根据实际需求合理选择变量类型,并确保数值不会超出定义的范围。
第六集 I/O输入输出
什么是GPIO,以及高电平和低电平的含义是什么?如何通过代码实现按键输入检测?
GPIO是通用输入输出端口的简称,是单片机引脚的一种功能表现,可以输入或输出高低电平。其中,高电平指的是端口上的电压接近于电源正极(VCC)的电压,对于3.3伏供电的单片机来说,高电平即为3.3伏;而低电平则是指接近电源负极(GND)的电压,即0伏。需要注意的是,虽然理论上高电平可以接近VCC,但实际中要考虑到单片机和IO口的极限电压,例如5.5伏,并非可以随意接任意电压。为了检测按键触发的信号,首先需要明确按键按下时引脚上的电压会变为低电平(小于0.99伏)。实验箱上的电路设计中,P32引脚经过一个300毫安电阻与按键相连,正常情况下引脚为高电平。当按键按下时,该引脚变为低电平,通过读取IO口电平(如P32)并与逻辑判断符(如等于0)对比,即可判断按键是否被按下。
单片机的IO口有哪几种模式,以及它们的特点是什么?
单片机的IO口有四种模式:准双向口、推挽输出、高阻输入和开漏模式。准双向口具有约20毫安的灌电流和微安级的拉电流;推挽输出可以达到20毫安的电流,适用于需要大电流控制的场合,如点灯实验;高阻输入和开漏模式则分别用于特定的功能需求,如减少功耗或实现特定的逻辑电平传输。
在3.3伏供电的单片机中,输入的高、低电平具体是多少?
在3.3伏供电的单片机中,输入高电平必须大于1.18伏或1.09伏,具体取决于是否打开了施密特触发器(默认上电复位后开启)。输入低电平的最大值为0.99伏。这些电压阈值是为了确保输入信号能够正确触发相应的输入事件,例如按键按下时,P32等准双向口引脚的电压会从高电平变为低电平。
如何开始编写代码并初始化代码文件?如何通过代码实现P32按钮按下时灯灭的功能?
首先,需要打开相应的文件夹并复制上一节课的内容到当前文件夹中,然后删除无关的上一节课代码,如XY变量等。接着,在代码编辑器中双击demo文件进行编辑,将上一节课的代码块复制进来,并为这段代码添加注释以便后续参考。实现这个功能只需复制之前亮灯的代码段并进行注释与取消注释的操作。具体来说,将原本的亮灯代码行注释掉,然后将该代码块下的大括号前添加一行P40等于0的命令(注意此行代码需放在大括号前且不在循环体内),这样就实现了按钮按下时灯灭的效果。
如何通过代码实现P32按钮按下时灯亮的功能?
要实现这一功能,首先判断P32按钮是否按下,使用if语句和逻辑判断符“==”来检查P32引脚是否为低电平(零)。如果按下,则设置P00引脚为低电平,使第一颗灯点亮;若未按下,则P00引脚保持高电平,灯保持熄灭状态。
如何在代码中配置和下载程序到目标设备?
在完成代码编写后,需要进行编译并下载程序到目标设备。在下载前确保配置正确,包括检查时钟设置、文件路径等。下载完成后,通过观察摄像头指示灯的变化验证功能是否正常,即按下P32按钮时灯应亮起。
如何利用变量实现按一下灯亮、再按一下灯灭的逻辑?
对于更复杂的任务,比如按一下灯亮、再按一下灯灭,可以采用一个标志位(变量)来记录按键的状态。首先定义一个无符号变量(U8类型)作为标志位,并初始化为0。当按键按下时,标志位取反,从0变为1。每按一次按钮,标志位状态就会取反一次,从而实现灯的开关控制。在代码中,根据标志位的状态输出相应的0或1至P0端口,以此达到按压次数决定灯的亮灭效果。
P32按钮在按下后为何会出现亮灭状态反复变化的情况?
这是因为P32按钮内部执行了一个取反的状态,即按下后,它的状态会在1和0之间不断切换。通过串口打印按钮的状态值(state),可以观察到其状态在按下时一直在改变。
如何判断按键松开?
要判断按键松开,需要用到一个名为WHRLE的指令。如果条件为真,则会一直执行相应的操作。在这个场景中,我们需要让程序在按下按钮后等待松开,可以通过添加WHRLE指令并设置合适的条件来实现。
如何消除按键抖动问题?
按键抖动会在按键按下和松开时产生短暂的电压波动。为解决这个问题,可以在检测到按键按下后的20毫秒内进行延时判断,确保只有在按键稳定按下时才执行相应操作。具体实现方式是在判断按键按下的地方加入一个20毫秒的延时,利用RSP软件中的软件延时计算器生成此延时指令,并注意系统初始化时将WTST设置为零。
如何初始化SWTST寄存器?
在官方实验包中,程序启动时会自动初始化SWTST寄存器为零,但这三句代码(设置指令延时参数、扩展XFR访问权限以及将CKCON寄存器写为零以提高访问速度)可以在代码中添加,以确保程序执行过程中SWTST寄存器处于正确的初始状态。
课后任务2参考:
if (P32 == 0) {
Delay20ms(); // 消抖
if (P32 == 0) {
state = (state + 1) % 8; // 状态循环0-7
P0 = 0xFF << (state + 1); // 计算LED模式
printf("state:%d, LEDs:0x%02X\r\n", state, P0);
while (P32 == 0); // 等待按键释放
}
}
第七集 定时器中断
在单核CPU中,如何解决一个任务执行期间无法执行其他任务的问题?
在单核CPU环境下,由于其只能执行一个任务,若某个任务需要持续执行(如从100数到0的循环),则无法在同一时间内执行其他任务。为解决这个问题,可以引入定时器概念,利用定时器中断来打断主循环,在特定时间点完成其他操作,从而实现任务间的切换和并行执行。
如何通过定时器实现对LED的3秒闪烁控制,并确保按下P32按钮时能正确计数并打印次数?
由于单核CPU在同一时间内只能执行一个任务,所以在用延时3秒的方式控制LED闪烁时,如果按下P32按钮,主程序无法立即响应并计数。为了解决这个问题,可以利用定时器中断技术,在定时器设定的3秒间隔内完成LED状态切换,并在按下按钮时通过中断机制记录按键次数并打印到串口。
如何使用ISP软件生成定时函数以实现定时器功能?
首先,在ISP软件中选择合适的时钟频率(本例中为24兆赫兹),然后配置定时器(如定时器0)为24位自动重载模式。通过定时器计算器功能,设定合适的定时时间(例如3秒),并勾选定时器中断选项。生成的中断函数可以在主函数之前进行初始化调用,确保定时器在正确的时间点触发中断,从而实现对LED的定时控制以及按键次数的准确计数和打印。
初始化函数为何建议放在后面执行?
初始化函数建议放在后面执行是因为其中包含了中断处理的逻辑,当单片机上电后会先执行主程序,直到遇到中断触发时才会跳转到中断函数执行,然后回到主程序继续执行。中断的存在就是用来在必要时打断主程序流程。
如何在代码中实现3秒取反LED灯状态一次的功能?
通过定时器函数实现3秒执行一次,利用已配置好的定时器中断,在24M时钟下,每3秒会触发一次中断并执行相应代码块,该代码块中对一个全局变量进行取反操作,并将结果输出到P00引脚。
如何在代码中通过按键控制变量count的值?
在特定的大括号内检测按键是否按下,若按下则消时20毫秒后判断按键是否仍被按下,并在按下状态下递增count变量的值。count是一个局部变量,仅在触发按键检测的大括号及其内部有效。
如何解决串口打印乱码的问题?
在编译器中存在对某些特殊字符处理的问题,会导致打印乱码。解决办法是在这些特殊汉字后面添加一个“\xfd”作为转义字符,确保正确显示。这个知识点来自于8051U手册的附录部分,手册可以帮助开发者解决类似编译器特有问题。
系统时钟是什么,它在定时器中的作用是什么?如何通过TM0PS寄存器来调整系统时钟的速度?
系统时钟(SYSCLK)是为定时器提供计数脉冲的源头,它是一个从0数到65536后发生溢出的计数器。在下载时选择的时钟频率下,比如24MHz意味着每秒钟或每微秒计数24次。这个时钟是系统中用于控制定时器启动、停止和计数的核心组件。TM0PS寄存器可以用来设置分频倍数,从而调整系统时钟的速度。当TM0PS为0时,系统时钟不分屏,即保持原速。若需要减慢时钟,可以通过修改TM0PS来实现,例如选择除以1或除以12的方式降低计数频率,其中1T模式意味着除以1,而12T模式则表示除以12。
FOSC是如何根据TM0PS的值来确定系统时钟的?
FOSC实际上是经过TM0PS加一后的系统时钟数值除以该值后的结果。例如,如果TM0PS为0,则FOSC等于系统时钟(如24MHz),若TM0PS为1,则FOSC变为系统时钟的一半,以此类推,以此实现对系统时钟的分频控制。
CTC(Counting Tracking Counter)是如何工作的,以及如何利用它来控制定时器0?
CTC在内部计数时,若设置为0,则定时器0将使用内部时钟进行计数;若设置为1,则会根据外部输入的int中断来控制定时器0。通过控制C杠T寄存器的值,可以实现对系统内部时钟的计数操作。
GATE位在启动定时器0时的作用是什么?
GATE位用于决定定时器0是否受外部输入中断控制。当GATE等于0时,通过设置TR0为1可以启动定时器0进行内部计数。若GATE等于1,则定时器0将受到外部中断输入的控制。
定时器0如何实现自动重载以达到16位定时效果?
定时器0拥有两个隐藏寄存器,每当技术结束时,会自动将这两个寄存器中的值重载到它们自身,实现加计数至65536后溢出并重新计数的过程。这种机制巧妙地实现了16位的自动重载定时功能。
在代码中如何配置定时器0的具体工作模式和参数?
在实际代码中,通过设置TM0PS(如本例中的0x5B,即91分屏)以及TMOD寄存器(如清空第四位得到十2T模式),来配置定时器0的工作模式和分频倍数。同时,还会调整其他相关寄存器(如TH0和TL0)以确定定时器的初始计数值,并确保其按照设定的模式(如16位自动重载模式)进行计数和溢出触发中断。
在初始化时,TF0和TR0如何配合工作以开始计时?
在初始化阶段,首先会清除TF0防止上电时进入中断。当GATE等于0时,会打开TL0,这样定时器就可以开始计时。同时,当ET0等于1时,会开启中断,从而在满足条件时触发一次中断。
如何通过公式计算定时频率,并举例说明计算过程?
定时频率的计算公式为:(系统时钟 / (TM0PS + 1)) * 65536 - *T。例如,带入具体数值计算后,得到的定时时间约为2.999982秒,这是一个在可接受范围内的误差。
16位自动重载定时器的工作原理是什么?
16位自动重载定时器从设定值递减到65536后置位一个标志位,每减至6536就会置位标志位一次,从而触发一次中断。当TH0和TL0计数到65536后,会触发一次中断,并且在下一次计数至65536时再次触发中断,以此循环工作。
函数定义、声明和调用的基本结构是什么?
函数定义包括返回值类型、函数名、入口参数以及函数体内的具体功能实现,以return语句作为结束。函数声明则是在被调用前的头文件或之前,仅包含函数名称、返回值类型和参数列表,以分号结尾。函数调用时需使用函数名加括号,如果有入口参数,则在括号内填入参数,多个参数间用逗号分隔。
如何解决未定义函数的问题以及何时需要使用函数声明?
如果在调用函数前没有定义,编译器将无法找到函数定义,这时就需要添加函数声明来告知编译器去查找相应函数定义。通常在函数调用之前且在相应函数定义之前添加声明最为常见,但也可以将定义放在后面,通过声明引导编译器定位到定义。
如何实现灯按一下点亮3秒后熄灭的功能?
首先灯按一下后,通过判断按键是否按下,然后直接将灯点亮(例如P00=0)。接着,在代码中设定一个定时器,在3秒后关闭定时器以使灯熄灭。具体实现方式是,在定时器启动后,当计时到3秒时,通过将定时器值设为0来停止计时和点亮状态。
如何控制按键按下后定时器的开启与关闭?
当按键按下时,初始化定时器并打开。若要实现定时关闭,可以利用一个全局变量来控制定时器的状态。每按下一次按键,该变量取反,当其为1时定时器开始运行,为0时则停止运行,并通过定时器控制灯的点亮与熄灭。
如何实现红蓝灯交替闪烁的效果?
通过创建一个全局变量,并在按下报警按钮时,根据变量的状态改变定时器的值,实现红蓝灯的交替闪烁。每按一次按钮,取反,从而控制定时器的启动和停止,进而达到红蓝灯闪烁的效果。
第八集 定时器周期性调度任务
上节课中,为什么会出现关于按键次数显示的问题?
这个问题出现在视频演示中,但实际上是在设置界面的数据分包显示和显示分包收发的时间功能开启了。关闭这两个选项后,按键次数显示问题即可解决。
在编程过程中,出现错误提示时应该如何查找和处理?
当代码编译出错时,首先需要找到错误提示行,尤其要注意提示中给出的关键词或上一行,检查符号、大小写以及中英文符号是否正确。例如,大写的U8与小写的u8定义不同,可能导致编译错误,因此务必确保函数和变量的大小写准确无误。
在编程中,如何避免因括号匹配问题导致的错误?
为了避免括号匹配错误,应保证每一对括号都清晰可见且相互对应。可以通过空格调整括号的位置,确保它们在代码中整齐对齐,这样可以减少遗漏或错误匹配的可能性。
如何利用定时器实现周期性任务?
利用定时器实现周期性任务时,可以设置一个计数变量每经过一定时间(如1毫秒)自加一次,当计数到达预设值(如300、600、900毫秒)时,执行相应的功能,并在执行后将计数变量清零以开始新一轮计时。通过这种方式,可以创建周期性执行特定任务的机制,适用于诸如LED闪烁控制等多种应用场景。
如何通过数组简化代码并实现不同方法的实现?如何定义和初始化一个数组?
在程序设计中,可以通过引入数组功能来简化代码并实现多种方法。例如,在一个任务中,可以定义一个数组变量替代多个相同类型的独立变量,这样不仅减少了冗余代码,还便于管理和操作。数组的定义需要包括类型、名称以及长度(即数组元素的数量),初始化时可以在定义时直接赋值,调用时通过变量名加索引的方式访问或修改数组中的特定元素。定义数组时,首先确定数组的数据类型,然后在其名称后添加中括号并指定数组长度,即数组内元素的数量。初始化时,在数组定义后的等号右侧填写一个数值序列来填充数组的所有元素,例如,声明一个长度为10的整型数组并初始化为1到10的数字序列。调用数组时,使用变量名结合索引(从0开始计数)来获取或设置数组中的特定值。
如何利用for循环对数组中的元素进行操作?
for循环是一种可以执行固定次数的循环结构,通过设置循环变量的初始值、循环条件和递增操作,可以在循环体内对数组元素进行一系列操作。例如,可以使用for循环遍历数组并逐个对数组元素进行加1操作,或者根据数组元素的状态控制LED的点亮或熄灭等操作。通过在循环体内调整数组元素的状态,可以实现诸如流水灯等动态效果。
在单片机中,如何理解数组索引从0开始以及其对计数的影响?
在单片机中,数组索引通常从0开始,这与u8等类型在内存中按顺序存储有关,它们的计数是从0到255。因此,在处理数组时,索引0代表数组的第一个元素,索引9则代表数组的第十个元素。这种从零开始的索引方式对于编程和数据处理具有重要影响,需要开发者注意并正确应用。
如何在计算器中将十进制数转换为16进制并写出对应代码?
可以通过计算器将十进制数转换为16进制。例如,对于4567,首先在计算器中输入高位在前的方式,即先输入七个一再加一个零,接着输入4567和一个零,这样就得到了0XFE。然后,我们可以通过将二进制数每一位作为16进制的特定位置(如0X01, 0X02, 0X04, 0X08, 0X10, 0X20, 0X40, 0X80)来简化16进制的书写过程。利用技巧,最低位是1248,通过组合这些基础变量就可以方便地写出任何16进制数。
如何根据16进制数控制P0端口上的LED灯流水效果?
首先定义一个u8类型的计数变量,并初始化为0。然后设置P0端口的八个灯(P00到P07)与该计数变量的关系,当计数变量递增到8时,将其重置为0。通过判断变量是否大于7来决定是否切换到下一个LED灯,并使用按位取反操作确保正确显示。这样,每500毫秒执行一次任务,输出当前状态到P0端口,实现流水灯效果。
如何处理按键按下状态以避免程序死循环?
为了解决按键按下导致程序死循环的问题,可以采用计数器技术。每隔一定时间(如10毫秒)检测按键状态,如果按键持续按下,则计数器加1;一旦按键释放,计数器清零。当计数器累积达到一定阈值(如5次连续按下)时,才判定为有效按键按下,并执行相应操作。这样,即使按键持续按下,其他任务也能正常执行,避免了程序死循环。
如何在保持独立任务调度的同时实现多个功能任务的协调运行?
在保持独立任务调度的原则下,各个任务如定时器任务、按键切换任务和LED灯指示任务可以相互独立运行,不会因其中一个任务阻塞而影响其他任务的执行。例如,在演示中,即使按键保持按下,其他任务仍然可以正常运行,这体现了良好的任务调度机制。同时,通过合理划分源文件(如config.c和config.h文件),可以将不同功能模块对应到不同的源文件中,便于管理和维护。
在创建点C和点H文件时,如何命名和调用它们以保持代码整洁?
在新建.C和.H文件时,应避免使用特殊字符,并确保两者名称一致,以便于调用时方便阅读。例如,可以命名为“xxx.h”和“xxx.c”。在调用时,通常以#开头的文件("#ifndef __XXX_H")来判断工程中是否已存在该H文件,如果没有则定义一个新文件,这样即使工程中有多个相同名称的点H文件,也会只执行一个。
如何将点C和点H文件添加到工程中,并正确引用它们?
首先,在创建并保存.C和.H文件后,需要将它们添加至工程中。具体操作是双击打开工程,找到相应的源文件(例如“第八个任务调度示例代码”中的点C文件),并将其双击添加进来。对于点H文件,需要在.C文件中使用"#include"进行引用,例如"#include "CONFIG.h""。同时,若点C文件也需要引用其他头文件,也可以通过"#include"进行调用。
如何利用结构体数组实现周期性任务调度,并举例说明?
在处理周期性任务调度时,可以定义一个结构体来封装各个任务的共同特征,包括定时器变量、基础目标设定、执行功能以及定时时间判断。例如,对于LED1、LED2和LED3的闪灯周期分别为3秒、6秒和9秒的情况,可以创建一个名为"typedef struct type task"的结构体,其中包含U8状态变量、U16定时计数器、重载计数器以及指向任务函数的指针。然后在点C和点H文件中声明和定义这些任务变量,并在主函数或其他相关函数中调用它们,从而实现各个任务的周期性调度。
如何定义并初始化一个变量,以及它在函数中的作用是什么?
一个变量通过逗号进行定义,它与函数名称对应,用来执行特定的函数。例如,若要定义一个与函数关联的变量,需将函数名称放置在变量处。值得注意的是,该变量在执行过程中,如果数值大于零,则执行减一操作,当减至零时,会重置为初始值十,并重新赋值。这个变量主要用于系统调度任务,通过定时器实现每1毫秒减1的功能。
如何将函数移植并安排在不同功能模块中?
首先将函数移植到底层的test.H文件中,以便在.C和其他地方都能调用。然后,根据函数的功能将其放置在相应的模块内,如计时功能的函数应放在slow.C中,因为它需要以1毫秒为周期执行;而判断主循环的函数则可以直接放在主循环内或定时器中。
如何编写用户函数并实现多任务调度?
创建新的文件(如IO.C和IO.H),并将所有IO操作放入其中。在test.C中,定义多个void函数(如LED0-blink、LED1-blink和LED2-blink),这些函数作为定时器任务,通过周期性计数从300毫秒开始,每达到零就运行一次,然后重新计数。同时,还可以编写按键检测任务,例如通过检测P32按钮的状态变化来执行不同的功能,进一步丰富了多任务调度系统的功能。
在编程实践中,如何处理文件名及编译错误等问题?
在编程实践中,尽量使用英文而非中文文件名以避免可能出现的乱码或冲突问题。当遇到编译错误时,需要查看错误信息并定位问题所在,例如更名文件、删除无用代码、正确配置任务调度系统等。最后,确保使用最新版软件进行下载编程,并注意在编写代码时遵循相应的规范和最佳实践。
第九集 数码管
在学习数码管内容之前,需要了解什么信息?
在开始学习数码管之前,建议大家先去论坛交流网址找到对应课程帖子,并查看顶楼上不定期更新的注意事项和常见错误。此外,所有课程配套文件,包括PPT和程序等,都可以在该帖子下方获取。
如何申请使用擎天柱板子?
要申请使用擎天柱板子,可以在特定渠道加对应客户经理进行申请。
数码管有哪些种类?
数码管外形多样,有数字型、字母型以及异形数码管等。它们的本质都是通过点亮内部LED灯来显示不同字符或图案。
数码管在单片机控制下是如何输出显示信息的?
数码管通过74595数电芯片将单片机输出的三个引脚信号转换为16个端口输出,利用移位寄存器原理逐个发送数据至数码管各段,实现数据的高位到低位传输,并通过特定的时序逻辑完成数据输出和显示。
数码管有哪些类型,它们是如何区分的?
数码管分为共阴极和共阳极两种类型。共阴极指的是所有负极接在一起,而共阳极则是所有正极接在一起。每种类型的数码管引脚连接方式不同,使用时需注意区分。
实验箱上的数码管是如何连接的,以及它的引脚对应关系是怎样的?
实验箱上的数码管通常采用74595数电芯片驱动,单个数码管有12个引脚,分别对应不同的笔画段和公共端。例如,A段对应某一引脚,而公共端则接在特定位置,不同类型的数码管(如单色或双色)会有不同的颜色显示。
在模拟的时序图中,数据位是如何从前往后送的?
数据位是通过SCK时钟信号控制,当SER为低电平时(即按键未按下),数据会从前向后逐位传送。例如,按下P32后,Q00端口输出零,然后随着SCK的跳变,数据一位一位地向右移位,并通过最前面的端口输出。
如何通过按键操作实现数据在移位寄存器中的移动和输出?
在单片机或接近单片机的芯片中,每个引脚状态可以自由缓存、移动且不会立即输出。通过按压特定按键(如P33作为RCK引脚),可以触发移位寄存器将内部缓存的数据逐位输出至相应引脚,从而控制LED的状态变化。
如何通过595移位寄存器实现对数码管的控制?
通过单片机的三个引脚控制595移位寄存器,首先按照特定顺序输入数据至寄存器,然后通过给RCK引脚发送高电平信号锁存数据。数码管的工作原理是共阳极结构,通过给阳极施加高电平,对应段码和位码的逻辑操作,可以点亮所需的数码管段,进而实现动态显示数字。
如何使用数组快速生成数码管的显示代码?
由于数码管有8个LED,需要一个八位变量来存储每个数字的段码。为了避免反复定义变量,可以创建一个包含0到9索引的数组,直接调用数组元素来显示所需的数字。数组可以通过工具自动生成,简化编程过程。
如何快速修改和定义引脚,以便于后续调用?
:可以采用在IO点H中定义引脚的方法,这样在修改时会非常方便。当需要在其他文件中调用变量名时,编译器会自动将其与P34等引脚关联起来,实现输出或读取。
如何编写控制595芯片的函数,并确保代码风格一致?
按照595芯片操作的风格来编写函数,例如将控制函数放在IO.C文件中,并定义为void类型,因为它不需返回值。使用类似“S”的命名,并确保大括号对齐,避免遗漏或错误。同时,对变量名、判断条件及循环计数器(如I++)进行自由修改,但要注意大小写保持一致,不可随意更改。
如何在595芯片数据输出过程中处理数据和引脚状态?如何初始化595芯片以及处理其上电状态?
通过for循环结构控制595芯片输出8位数据,每次循环中将数据左移一位,并利用CY获取最高位状态。输出数据时,通过IO点H复制相应引脚名称到L点C中,然后先写入数据到引脚上,再给出上升沿时钟信号SCK,最后清零SCK以便准备下一次输出。在主程序中调用一个名为unit的595初始化函数,它可以为空参数,作用是将595芯片的所有引脚设置为低电平状态,确保上电后数据无效。通过复制、粘贴并格式化代码,实现对595芯片所有引脚的初始化操作。
如何实现595芯片数据的输出和控制数码管显示?
通过调用之前定义的595发送函数,先发送第2个595的数据,再发送第1个595的数据,然后分别控制595芯片输出段码和位码,从而实现数码管的显示控制。在主函数中,首先进行端口初始化,然后在一个静态显示的任务中调用相应函数,以实现数码管的动态显示效果。
在编程过程中遇到错误时,应该如何处理?
当在编程过程中遇到错误时,不要慌张。应逐个排查并注释或屏蔽掉可能出错的部分,通过一步步修正来解决。例如,在提到的案例中,发现编译错误后,先定位到具体行数(如84行),修改错误的符号使用,并重新编译以消除错误。
如何排查并修复代码中的问题,确保摄像头数据正确显示?
首先检查并确保摄像头数据接收区已清空,并下载正确无误的程序代码。之后通过观察摄像头显示的数据是否正常(例如是否显示乱码),进一步分析任务调用时是否存在未屏蔽的之前任务影响。接着逐个排查IO点、595输出以及相关引脚设置是否正确,最后发现并修正错误代码(如将“date”改为“CY”)以恢复正常显示。
如何实现数码管的静态显示以及动态显示?
静态显示时,可以使用数组定义并赋值来控制每个数码管的显示内容,如用0x01代表最低位点亮。动态显示则需循环显示每个数码管,并在每个数码管显示后添加延时,确保刷新率高于人眼分辨率(即每秒至少切换12次以上)。具体实现步骤包括定义全局变量记录当前显示的数码管位置,通过变量递增来切换不同的数码管,并在显示过程中加入延时控制,同时注意防止变量溢出。
如何利用变量控制数码管显示时、分、秒信息?
为实现数码管显示时、分、秒信息,首先定义三个变量分别存储时、分、秒信息。然后根据不同变量值,通过数组输出相应的数字,并利用条件语句根据变量的大小输出对应位数的数字。同时,创建一个计时任务(如名为tim_count的任务),每秒钟执行一次,增加秒的计数,并在秒达到60时清零并相应增加分钟计数,以此类推实现时、分、秒的正确显示与更新。
在编程中,如何处理小时、分钟和秒钟的溢出问题,以确保时钟正确运行?
当秒钟达到60时,需要将秒钟清零并加1到分钟;当分钟达到60时,同样进行清零操作并将小时加1。对于小时,若达到24,则应清零并重新计时。这些操作在一秒钟内由函数自动完成。
数码管动态显示是如何实现的?
数码管动态显示通过查阅一个码表来实现,码表中对应每个数值的索引号和显示内容。例如,在特定位置添加新的列以显示所需数值,并确保索引号正确对应。
数码管是否已经不再常用?
数码管尽管有人认为其不常用,但实际上在工业仪表等领域销量巨大,是非常实用且稳定的产品,因此学习数码管是非常必要的。
虚拟显示接口是如何使用的?
虚拟显示接口可以通过ISP软件中的工具实现,首先分析协议并了解命令格式。例如,发送特定命令头(如4CH、45H、44H、28H)后,按照协议规定顺序发送数据长度、端口屏蔽位及端口数据。通过库函数封装好的函数可以直接调用,指定要控制的端口和输出状态,从而实现虚拟LED的点亮与动态效果演示。
如何用模拟器演示流水灯效果?
在模拟器中,首先编写代码定义并初始化变量,如U8类型的状态变量。通过连续改变状态变量的值来控制P2端口(或实验箱的P0端口)上的LED逐个点亮和熄灭,从而实现流水灯效果。下载程序至硬件后,在调试接口观察到相应的LED动态变化。
实验箱的流水灯如何通过P0端口实现?
将实验箱的流水灯连接到P0端口上,通过0x01地址控制P2端口,然后进行相应的编程操作即可实现实验箱的流水灯效果。
如何设置任务以每秒修改一次数码管上的时间显示?
在编程时定义一个任务,设置计时周期为1000毫秒(即一秒钟),并在任务中不断更新数码管上的时间显示。
如何一次性向数码管发送多个数据并控制其显示内容?
在代码中定义一个数组来存储要发送的数据,由于数码管一次可以显示八个位,因此只需填写一次数组即可一次性显示出所有数码管的数据,从而实现同时显示小时、分钟、秒等信息。
如何通过数组索引获取小时、分钟、秒的具体数值并在数码管上显示?
通过数组获取相应数值(如小时的十位和个位、分钟、秒的十位和个位等),然后利用数码管的段码功能将其转换为相应的显示码,最后发送到数码管上进行显示。
如何解决全局变量与局部变量的作用域冲突问题?
在不同函数或代码块中定义的局部变量具有不同的作用域,它们不会相互冲突。即使两个地方都定义了名为code的变量,只要它们分别存在于各自的函数或大括号内,就不会产生冲突。
如何通过虚拟接口与数码管进行数据通信?
利用段码显示将数据发送至数码管,确保数据通过相应的接口协议正确地从上位机传输到数码管进行显示。同时,可以灵活地通过改变代码参数或使用手册提供的功能来实现对数码管的各种控制和显示需求。
如何在没有实体数码管的情况下使用虚拟接口和上位机显示数码管信息?
利用专门开发的虚拟接口和上位机软件,可以直接发送数据来控制数码管显示。例如,在代码中编写针对八段数码管的控制程序,一次性发送八个数据进行显示,并根据实际需求调整数码管的显示内容。
页:
[1]
2