实验题目:STC-BSP 余下API函数及综合应用
实验时间:2022.3.7~2022.3.20(第4周日)
实验地点:在规定时间内独立寻找合适的实验地点,并在规定时间内完成
1.STC-B学习板(每个学生在2021年暑假小学期自己做) 2.个人电脑:自备 3.Keil、ISP、CH340驱动软件:自备 4.STC-BSP及Demo 程序:教师提供 5.“STC_B软件支持包使用说明:教师提供 6.C51语言语法:课程提供参考电子书或自学 7.Demo1~Demo5源程序:教师提供(Demo实验结束后提供3源程序) 8.Demo4所需直流电机模块:工程中心C栋215助教处临时借用 9.Demo5.485通信连接:工程中心C栋215助教处临时借用
实验目的:
1.学习和熟悉STC-BSP(“STC-B学习板板级软件开发支撑包剩余(实验1外)所有模块API函数及其使用; 2.掌握事件和事件的回调函数编程机制和使用; 3.认识“STC-B熟悉并掌握学习板中的几种通信方法; 4.学习在STC-BSP在支持下,设计应用程序。
实验内容:
1.阅读《“STC_B学习板软件支持包使用说明书中剩余(实验1除外)的所有模块说明书,阅读实验2提供Demo源程序(Demo1、2、4、5)编写程序测试模块提供的各种函数和方法。除了熟悉的正函数使用方法外,本实验还关注事件和事件的回调函数方法; 2.阅读Demo5.与同学合作验证相关资料和程序Demo 5.完成通信和网络功能,学习和理解相关原理,记录实验过程和现象。 3.实验2现场验收内容:设计和编写具有一定功能和目的的应用程序,并在STC-B实现学习板;要求:包括通信(串口1、串口2、485或Ir)、操作包含按钮或导航按钮。 4.选择:认识和验证:Demo3功能(Demo目前只提供下载HEX实验2结束后提供参考源程序的文件Demo2源码,看能不能编程Demo3.相同的功能和效果(实验二加分项,培养嵌入式应用程序和实用程序编写能力)
实验过程、步骤、现象、结果:
1,ADC.h模块:
ADC模块用于“STC-B上和学习板ADC相关电路:温度Rt、光照Rop、导航按键Nav、扩展接口EXT上的ADC转换。提供ADC模块初始化函数,2个应用函数,2个事件。 初始化函数:AdcInit(char ADCsel) 函数参数: ADCsel选择扩展接口EXT是否用作ADC功能,取值有 ADCincEXT : 包含扩展接口EXT设置ADC功能(EXT上P1.0、P1.1不可作数字IO功能使用) ADCexpEXT : 不包括扩展接口EXT设置ADC功能(EXT上P1.0、P1.1可作数字IO功能使用) 选择前者可以使用扩展模块,后者则无法使用 两个应用函数: struct_ADC GetADC():获取ADC值。ADC结构信息如下: typedef struct //ADC转换结果 { unsigned int EXT_P10; // 扩展接口EXT上P1.0脚ADC(10bit) unsigned int EXT_P11; // 扩展接口EXT上P1.1脚ADC(10bit) unsigned int Rt; // 热敏电阻上ADC(10bit) unsigned int Rop; // 光敏电阻上ADC(10bit) unsigned int Nav; // 导航按键上ADC(10bit) } struct_ADC;可用于获取扩展模块的数据或每个数据ADC相关电路数据 char GetAdcNavAct(char Nav_button):获取导航按钮(包括)K3)状态 函数参数:Nav_button:指定要获得状态的导航按钮。 enumAdcNavKey3(K3键), enumAdcNavKeyRight(右按), enumAdcNavKeyDown(下按), enumAdcNavKeyCenter(中心按), enumAdcNavKeyLeft(左按), enumAdcNavKeyUp(上按). 注意在使用ADC模块后Key模块的Key3相关函数命令不能使用 提供的两个事件是: 导航按键事件:enumEventNav 当导航按钮向个方向或按钮时K按下或抬起动作时,会产生导航按键事件enumEventNav。响应导航按键事件的用户回调函数由用户编写,由用户编写sys提供的SetEventCallBack()函数设置响应函数. 扩展接口EXT上P1.0、P1.两个端口有新的AD值事件:enumEventXADC 当ADC模块对P1.0、P1.1进行ADC转换获得了他们新的ADC结果时,将产生enumEventXADC通知用户处理事件。enumEventXADC事件的用户回调函数由用户编写,并有sys提供的SetEventCallBack()函数设置响应函数. ADC模块对P1.0、P1.1进行ADC转换速度为3mS,也即每3mS或者每秒333次转换. 函数功能测试: 将ADC光强和模块的温度Nav值输出在数值输出:
测试结果如下:3~6位表示光强,用物品遮挡和放置强光时,结果会相应升高降低,Nav当我们按下不同的导航按钮时,值会显示不同的值。这些值对应于导航按钮中每个按钮的状态信息。温度尚未转换为摄氏度,目前显示在室内ADC加热后(用手)值降低550左右
导航按键事件的回调试验:
按下导航按钮时,Led灯亮起,如代码所示LED灯。测试结果符合预期:
2.DS1302.h模块:
DS控制1302模块STC-B学习板”上DS1302芯片操作。 DS1302提供RTC(实时时钟)和NVM(非易失存储器)功能(断电后,RTC和NVM依靠纽扣电池BAT保持工作)RTC提供年、月、日、周、时、分、秒功能;NVM提供31 Bytes非易失存储功能(地址为0~30)。 地址为30的单元DS1302Init()检测函数DS用户不能使用1302是否断电 DS1302模块提供1个驱动函数和4个应用函数: (1) void DS1302Init(struct_DS1302_RTC time):DS1302驱动函数。DS1302需要一次初始化和驱动函数 函数参数:结构struct_DS1302_RTC time 如果DS1302断电(初始检测)RTC数据失效),参数time定义时间的初始化RTC (2)struct_DS1302_RTC RTC_Read(void):读取DS1302内部实时钟RTC内容 函数返回值:结构struct_DS1302(见结构struct_DS1302定义) (3)void RTC_Write(struct_DS1302_RTC time) :写DS1302内部实时时钟RTC内容 函数参数:结构struct_DS1302 time(见结构struct_DS1302定义) (4)unsigned char NVM_Read(unsigned char NVM_addr): 读取NVM指定地址内容 函数参数: NVM_addr:指定非易失存储单元地址,有效值0~30(共31个单元) 函数返回值:当函数参数正常时NVM对应单元的存储值(1)Byte) 当函数参数错误时,返回enumDS1302_error (5)unsigned char NVM_Write(unsigned char NVM_addr, unsigned char NVM_data):向NVM一个指定地址写入新值 函数参数:NVM_addr:指定非易失存储单元地址,有效值为0~30(共31个单元)。 NVM_data:待写入NVM单元新值(1Byte) 函数返回值:当函数参数正常时enumDS1302_OK 当函数参数错误时,返回enumDS1302_error 结构struct_DS1302_RTC定义: typedef strct { unsigned char second; //秒(BCD码,以下均为BCD码) unsigned char minute; //分 unsigned char hour; //时 unsigned char day; //日 unsigned char month; //月 unsigned char week; //星期 unsigned char year; //年 } struct_DS1302_RTC; BCD码为2进码十进数,简单来说对于4位的二进制来说,只采用00001001的数字其他舍弃就是最简单的BCD码即只表示010的数字a~f不进行表示 测试函数:
初始界面如图所示,掉电后结果不变,按下按键日期发生变化,同样掉电后结果不发生改变
测试非易丢存储器:
初始情况:断电后结果不变 按下按键后结果如图:断电后结果不变
3.EXT.h模块
EXT模块用于控制“STC-B学习板”上扩展接口EXT上相关操作。 EXT模块根据应用需要,在外接相应模块或部件后,可实现多种相应功能。这里提供部分应用驱动和API函数。 EXT模块这里提供1个驱动函数和若干个应用层API函数。 EXT模块的API函数不是同时有效的,而是根据初始化函数参数不同而分别有效。 测试enumEXTWeight()功能:
显示情况如下:初始值并不为0,这是因为函数本身没有进行清零标定的工作 所以后续想要使用该模块还需要进行标定工作。
测试enumEXTPWM功能:
效果为当pwm1比pwm2差距20及以上时电机会进行旋转,当pwm1>pwm2 时逆时针旋转,反之顺时针旋转 测试enumEXTDecode
实验结果无论顺时针或逆时针,只要改变旋转角度都会显示正值,当不旋转时显示0。 测试enumEXTUltraSonic超声波测距
测试结果如图能过正确显示超声波模块到障碍物的距离
4.Hall.h模块
Hall模块用于获取“STC-B学习板”上hall传感器状态。hall模块共提供1个加载函数、1个应用函数,一个Hall事件:enumEventHall (1)HallInit():hall模块初始化函数 (2)unsigned char GetHallAct(void):获取hall事件。 函数返回值: enumHallNull(无变化) enumHallGetClose(磁场接近) enumHallGetAway(磁场离开) 查询一次后,事件值变成enumEventHall (仅查询一次有效) (3)hall传感器事件: 当Hall检测到有"磁场接近"或"磁场离开"事件时,将产生一个Hall传感器事件(enumEventHall).响应事件的用户处理函数由用户编写, 并有sys中提供的SetEventCallBack()函数设置事件响应函数. 测试函数:
实验结果:磁铁靠近时数码管会显示1,初始情况显示0
5.IR.h模块
IR模块用于控制“STC-B学习板”上红外发送与接收控制,支持PWM、PPM红外编码协议的发送,PWM红外编码的接收,可用于制作红外遥控器、红外通信等。 IR模块提供1个驱动函数、5个API应用函数、1个红外接收事件(enumEventIrRxd:红外Ir上收到一个数据包)。 IR模块已不与串口通信(uart和uart2)冲突,可用与它们同时工作。(以前冲突) API函数: (1) void IrInit(unsigned char Protocol):IR模块初始化函数。 函数参数:unsigned char Protocol,定义红外协议。 Protocol 暂仅提供取值:NEC_R05d(定义红外协议基本时间片时长 = 13.1Protocol uS) (2) char IrTxdSet(unsigned char pt,unsigned char num):以自由编码方式控制IR发送:可用于编写任意编码协议的红外发送,如各种电器红外遥控器等 函数参数:unsigned char pt,指向待发送红外编码数据的首地址。编码规则如下: 码i红外发送时长,码i红外发送停止时长 //单位:协议基本时间片的个数值,最大255。如当协议基本时间片为0.56mS时,数值1代表0.56mS时长,3代表1.68mS时长 unsigned char num,待发送红外编码数据的大小(字节数) 函数返回值:enumIrTxOK:调用成功,即所设定的发送数据包请求已被系统sys正确接受,sys将尽硬件资源最大可能及时发送数据。 enumIrTxFailure:调用失败(主要原因是:红外发送正忙(上一数据包未发完)、或红外正在接收一个数据包进行中 (3) char IrPrint(void pt, unsigned char num)://以NEC的PWM编码方式发送数据,可用于符合该函数发送格式的部分电器遥控器;与GetIrRxNum()、SetIrRxd()配合,可进行红外双机通信;等 //红外发送数据格式为:引导码:发(16基本时间片),停(8基本时间片)。0.56mS时:发9mS、停4.5mS 数据编码:“0” – 发(1基本时间片),停(1基本时间片) “1” – 发(1基本时间片),停(3基本时间片) 先发高位、后发低位 结束码:发(1基本时间片),停(1基本时间片) //非阻塞函数,该函数从被调用到返回大约1uS左右时间,但所指定的数据经红外发送完毕则需要较长时间(每字节大约需要10mS量级时间)。 函数参数:void *pt :指定发送数据包位置(数据包不含引导码、结束码信息,仅待发送的有效数据) unsigned char num:发送数据包大小(字节数,不含引导码、结束码) 函数返回值:enumIrTxOK:调用成功,即所设定的发送数据包请求已被系统sys正确接受,sys将尽硬件资源最大可能及时发送数据。 enumIrTxFailure:调用失败(主要原因是:红外发送正忙(上一数据包未发完)、或红外正在接收一个数据包进行中(同IrTxdSet()函数返回值) (4) void SetIrRxd(void *RxdPt,unsigned char RxdNmax):设置红外接收数据包存放位置、每个数据包最大字节数。 收到一个数据包(至少1字节数据)时将产生numEventIrRxd事件。与它机IrPrint()函数配合,可实现红外数据通信 函数参数: void char *RxdPt:指定接收数据包存放区(首地址) unsigned char RxdNmax:指定每个数据包接收最大字节数。接收数据如果字节数超出,超出部分将被忽略。该值定义接收数据包最大值,以免超出而影响程序其它数据 (5) unsigned char GetIrRxNum(void):获取收到的红外接收数据包实际字节数。与SetIrRxd()配合,可实现红外数据包接收。(它机应使用IrPrint()函数发送数据包) 返回取值 <= Ir接收缓冲区最大字节数(RxdNmax定义)。如果实际红外数据包字节数大于RxdNmax,收到的多余字节数将不被存储(也不进行计数) 函数返回值:红外接收数据包大小(字节数)。 当收到一个数据包的numEventIrRxd事件产生后,可用该函数获取红外接收数据包的大小(字节数)。其它时间访问,其值不确定 (6)char GetIrStatus(void): 获取Ir状态 函数返回值:enumIrFree:红外空闲 enumIrBusy:红外正忙(正在发送数据包,或正在接收数据包) (7)红外接收事件enumEventIrRxd:红外Ir上收到一个符合格式的数据包(红外格式见IrPrint()函数说明)。如果接收数据包实际字节数大于Ir接收缓冲区最大字节数(RxdNmax定义),也在收到数据包结束符后产生enumEventIrRxd事件 测试函数:
测试结果如图,当按下Key1后收到红外信号后,数码管上的数字加一。
6.M24C02.h模块
M24C02模块用于控制“STC-B学习板”上IIC接口的非易失存储器(NVM)M24C02芯片操作。 M24C02提供2K bits(256 Bytes)非易失存储器(NVM)功能(非易失存储器单元地址为:00~0xff)。 M24C0402模块共提供2个应用函数(本模块不需要初始化) (1)unsigned char M24C02_Read(unsigned char NVM_addr): 读取M24C02一个指定地址内容 函数参数: NVM_addr:指定非易失存储单元地址,有效值00~0xff(共256个单元) 函数返回值:返回M24C02中对应单元的存储数值(1Byte) (2)void M24C02_Write(unsigned char NVM_addr, unsigned char NVM_data):向M24C02一个指定地址写入新值 函数参数: NVM_addr:指定非易失存储单元地址,有效值:00~0xff(共256个单元) NVM_data:待写入M24C02单元的新值(1Byte) 补充说明: M24C02为非易失性存储器,其主要特点是:存储的内容在断电后能继续保存,一般用于保存断电需保留的工作系统参数; 但读、写M24C02内部每一个字节均需要花费一定时间(每次读写操作大约数十uS,写周期为5~10mS),且有”写“寿命限制(每一单元大约”写“寿命为10万次量级寿命); 与DS1302内部NVM区别:容量大(M24C02提供256字节,M24CXX系列最大可提供64K字节),但有“写”寿命限制(一般为数十万次“写”寿命“,且写周期长(5~10mS)因此,两次写操作之间需间隔5~10mS以上; 实验效果与DS1302类似都可以做到掉电保存效果
7.StepMotor.h模块
StepMotor用于STC-B板控制步进电机。共提供1个驱动函数、3个应用函数:(1)StepMotorInit():步进电机模块驱动函数 (2)SetStepMotor(char StepMotor,unsigned char speed ,int steps ) 指定步进电机、按指定转动速度、转动指定步 函数参数:StepMotor 指定步进电机,取值(enum StepMotorName中定义) enumStepMotor1: SM 接口上的步进电机 enumStepMotor2: 此时,用L0~L3四个LED模拟一个4相步进电机 enumStepMotor3: 此时,用L4~L7四个LED模拟一个4相步进电机 Speed:步进电机转动速度(0~255),单位:步/S。 (实际每步时间=int(1000mS/speed) mS),与设置速度可能存在一定误差 Step:步进电机转动步数(-32768~32767),负值表示反转 函数返回:enumSetStepMotorOK: 调用成功(enum StepMotorActName中定义) numSetStepMotorFail:调用失败(电机名不在指定范围,或speed=0,或调用时正在转动) (3)EmStop(char StepMotor) 紧急停止指定步进电机转动 函数参数:StepMotor 指定步进电机。函数参数不对将返回0值。 函数返回:剩余未转完的步数 (4)GetStepMotorStatus(char StepMotor) 获取指定步进电机状态 函数参数:StepMotor 指定步进电机 函数返回:enumStepMotorFree:自由(enum StepMotorActName中定义) enumStepMotorBusy,忙(正在转动) enumSetStepMotorFail:调用失败(步进电机名不在指定范围)
实验效果:电机逆时针转动(但是速度为200了转速看起来还是很慢) 8.Uart2.h Uart2模块提供Uart2模块初始化函数、3个应用函数,1个事件(enumUart2EventRxd): (1) Uart2Init(unsigned long band,unsigned char Uart2mode):Uart2模块初始化函数。 函数参数:unsigned long band:定义串口2的通信波特率(单位:bps)(固定8个数据位、1个停止位,无奇偶校验位) unsigned char Uart2mode:定义串口2位置 取值:Uart2UsedforEXT —— 串口2在EXT扩展插座上 Uart2Usedfor485 —— 串口2用于485通信(半双工。发送数据包时不能接收数据) (2) void SetUart2Rxd(char *RxdPt, unsigned int Nmax, char *matchhead, unsigned int matchheadsize); 设置串口2接收参数:数据包存放位置、大小,包头匹配字符、匹配字符个数。收到符合条件的数据包时将产生enumEventRxd事件。 函数参数: char *RxdPt:指定接收数据包存放区(首地址) unsigned int Nmax:接收数据包大小(字节数),最大65535 char matchhead: 需要匹配的数据包头(首地址) unsigned int matchheadsize:需要匹配的字节数 补充说明: Nmax=1:为单字节接收,即收到一个字节就产生enumEventUart2Rxd事件(如果定义了匹配,还需满足匹配条件); 0 < matchheadsize < Nmax:要求接收数据中连续matchheadsize个字节与matchhead处数据完全匹配,才在收到Nmax数据时产生enumEventRxd事件; matchheadsize = Nmax:设定接收数据包完全匹配 matchheadsize=0 或 matchheadsize > Nmax:将不做匹配,接收到任意Nmax数据时产生enumEventRxd事件; 在enumEventRxd事件发出后,接收到的数据包应及时使用或取出,收到下一个数据时将破坏和覆盖前面收到的数据包 (3)char Uart2Print(void *pt, unsigned int num):发送数据包,非阻塞函数(即函数不等到所设定任务全部完成才返回),该函数从被调用到返回大约1uS左右时间。 函数参数: void *pt :指定发送数据包位置 unsigned int num:发送数据包大小; 函数返回值:enumTxOK:调用成功,即所设定的发送数据包请求已被系统sys正确接受,sys将尽硬件资源最大可能及时发送数据。 enumTxFailure:调用失败(主要原因是:串口正忙(上一数据包未发完) 补充说明:串口上发送1个字节数据大约需要时间0.1mS~10mS(视所设定的波特率)。 (4)char GetUart2TxStatus(void): 获取Uart2发送状态 函数返回值:enumUart2TxFree:串口2发送空闲 enumUart2TxBusy,串口2发送正忙 (5) Uart2接收事件:enumUart2EventRxd。表示收到了一个符合指定要求(数据包头匹配、数据包大小一致)的数据包。 补充说明:串口(1和2)上收到的两个数据包之时间间隔要求不小于1mS(原因:系统内部调度方法限制) 测试函数:蓝牙方面的测试:
完成初始化后就可以接收到蓝牙模块进行配对了
测试485情况下的代码:
当Key1按下后对方的板子上数码管数字会加一,实验结果:
9.Uart1.h模块
Uart1模块提供Uart1模块初始化函数、3个应用函数,1个事件(enumEventRxd): (1) Uart1Init(unsigned long band):Uart1模块初始化函数。 函数参数:unsigned long band定义串口1的通信波特率(单位:bps)(8个数据位、1个停止位,无奇偶校验位) 函数返回值:无 (2) void SetUart1Rxd(char *RxdPt, unsigned int Nmax, char *matchhead, unsigned int matchheadsize); 设置串口1接收参数:数据包存放位置、大小,包头匹配字符、匹配字符个数。收到符合条件的数据包时将产生enumEventRxd事件。 函数参数: char *RxdPt:指定接收数据包存放区(首地址) unsigned int Nmax:接收数据包大小(字节数),最大65535 char matchhead: 需要匹配的数据包头(首地址) unsigned int matchheadsize:需要匹配的字节数 补充说明: Nmax=1:为单字节接收,即收到一个字节就产生enumUart1EventRxd事件(如果定义了匹配,还需满足匹配条件); 0 < matchheadsize < Nmax:要求接收数据中连续matchheadsize个字节与matchhead处数据完全匹配,才在收到Nmax数据时产生enumEventRxd事件; matchheadsize = Nmax:设定接收数据包完全匹配 matchheadsize=0 或 matchheadsize > Nmax:将不做匹配,接收到任意Nmax数据时产生enumEventRxd事件; 在enumEventRxd事件发出后,接收到的数据包应及时使用或取出,收到下一个数据时将破坏和覆盖前面收到的数据包 函数返回值:无 (3)char Uart1Print(void *pt, unsigned int num):发送数据包,非阻塞函数(即函数不等到所设定任务全部完成才返回),该函数从被调用到返回大约1uS左右时间。 函数参数: void *pt :指定发送数据包位置 unsigned int num:发送数据包大小; 函数返回值:enumTxOK:调用成功,即所设定的发送数据包请求已被系统sys正确接受,sys将尽硬件资源最大可能及时发送数据。 enumTxFailure:调用失败(主要原因是:串口正忙(上一数据包未发完) 补充说明:串口上发送1个字节数据大约需要时间0.1mS~10mS(视所设定的波特率)。 (4)char GetUart1TxStatus(void): 获取Uart1发送状态 函数返回值:enumUart1TxFree:串口1发送空闲 enumUart1TxBusy,串口1发送正忙 (5) Uart1接收事件:enumEventUart1Rxd。表示收到了一个符合指定要求(数据包头匹配、数据包大小一致)的数据包。 补充说明:串口(1和2)上收到的两个数据包之时间间隔要求不小于1mS(原因:系统内部调度方法限制) 测试函数:
按下按键后,电脑可从串口(初始化时波特率要与串口助手一致)得到1,1,1,1,1,1的数据(6个1是发送数据地址中的数据) 电脑先串口发送数据后板子接收到信息后触发回调函数,板子上数码管的数字加一。 实验效果:
10.Vib.h模块
Vib用于获取"STC-B学习板"上Vib传感器状态.提供一个模块加载函数和一个应用函数,一个Vib事件enumEventVib: (1)VibInit():振动传感器Vib模块初始化函数; (2)char GetVibAct():获取Vib事件。 函数返回值:返回当前Vib传感器事件,返回值:enumVibNull——无,enumVibQuake——发生过振动 查询一次后,事件值变成 enumVibNull (仅查询一次有效) (3)Vib传感器事件enumEventVib: 当Vib检测到有”振动“事件时,将产生一个”振动事件“,响应事件的用户处理函数由用户编写, 并有sys中提供的SetEventCallBack()函数设置. 测试函数:
当板子每震动一次,数码管上的数字加一 实验效果:每次震动时数字加一(有时不稳定会加2)
阅读实验二提供的Demo源程序(Demo1、2、4、5)
该回调函数使用GetADC(),获取温度,光强等属性值,然后将其中的光照强度进行输出在数码管中,然后进行判断如果光强大于50就会将LED左边的灯点亮并发出警报,小于20时将LED右边的灯点亮并发出警报,不过警报频率较小
两个回调函数,按键回调函数通过检测按键1和按键3的按下情况将各自的标志位改变,如果标志位为0,按下后(相当于此时开始计时)会将前面的计数清零,蜂鸣器同时会发声。时间回调函数负责再标志位为1时,每次调用时间回调函数时进行计数加一,并将计数结果显示在数码管上。
该主要代码使用SetPWM()API函数发送指定占空比和频率的数据控制电机进行旋转,按下按键后可以通过改变占空比来控制电机旋转。时间回调函数则进行SetPWM()的设置(通过将占空比进行交换做到将发送信号的数据频率相反的功能,从而使电机逆反向旋转)同时将电机占空比输出到数码管上。
设置时通过在校验码中加入myID变量,来确定多线连接可以准确向目标板子发送数据,数据到达后取出其中的后三位(前3位为校验码)分别为旋转方向和速度 然后通过时间回调函数触发电机的设置来完成将收集到的数据应用到电机中,同时在本地板端可以通过key1按键来改变dir从而触发电机旋转的反向。
阅读Demo5相关资料与程序,与同学合作验证Demo 5完成的通信与组网功能,学习和了解相关原理,记录实验过程和现象。
在Demo5中将汇聚节点代码烧录到一个板子中与电脑连接,485的代码烧录到另一个板子中。如此在串口1中输入数据aa 55 01 01 40 00,那么汇聚节点会转发到串口2,485通信中,电机控制属性与其一致。 结果如图所示:这里没有电机将数据结果显示在数码管上,第二个电机中只需在串口1的数据中将第3个字节改为02即可
红外测试:将ID改为0x82,汇聚节点会将数据转发给红外进行发送,结果如图所示显示 方向001。
设计与编写有一定功能、目的的应用程序,并调式和在“STC-B学习板”上实现;
简单功能案例: 按下一个 板子上的key1后另一个接收到到红外信号的板子,通过判断发送的数据是否正确(全为1)如果正确则数码管上的数字加一 实验效果:一个板子按下5次key1另一个按下3次 较为复杂功能案例: 在学习板上按键key3为切换单机和联机模式,初始为单机模式,在单机情况下游戏初始界面如下图:
此界面为游戏准备阶段右边的7个数码管为上次游戏所得分数这里初始为0,最左边的数码管显示的是“拼图碎片”,在游戏开始时如上图右图所示通过导航按键的上下可以操作最左边的“拼图碎片”同时左边会随机出现一个缺一角的“图片”当左边的拼图碎片与右边的图形合在一起恰好形成一个带小数电的数字8时(即合起来恰好数码管全点亮)则得一分,并继续游戏,在游戏中按下key1会暂停游戏,这时数码管上回固定你的拼图碎片同时在右侧显示出目前的得分,再次按下key1后可以继续游戏(此时会触发游戏暂停惩罚图形会往前移一格)。若失败则学习板发出提醒声音游戏结束,在右侧显示本次游戏的得分(如下图)。(与暂停时情况类似但此时key1无法开始游戏),在游戏任何时候按下key2可以重新开始游戏(但分数会归0)。
在游戏进行时随着游戏得分的增加,图形移动速度也会增加,得分每多5分游戏速度会升一级最高5级。 游戏任何时候按下key3切换模式,切换到联机模式时,在联机模式中双方初始状态如下
左侧数码管显示为双方目前的得分,右边的两个数码管靠左的数码管显示的是设置的难度等级,最右边的数码管显示的是对方下一次游戏时会出现的图形。此时通过key1,key2可以对难度和图形进行设置,设置完成后往下按下导航按键,此时对方进入游戏,出现的难度和图形与自己设置一致,设置难度越高对方成功拼图后得分也越高,对方若失败则学习板发出提醒声音对方游戏结束 对方此时不能再进入游戏得分但可以继续设置难度和图形发送,当双方玩家均失败后得分高的玩家会播放胜利音乐,若分数相同则双方都播放音乐。播放音乐过程中或播放结束都可以重新开始游戏,而一旦任何一方重新开始游戏双方分数都会清零然后重新开始游戏。
工程代码:
#include "STC15F2K60S2.H" //必须。 #include "sys.H" //必须。 #include "displayer.H" //可选,如果使用
显示模块 #include "Key.H" //可选,如果使用按键模块 #include "beep.h" //可选,如果使用蜂鸣器模块 #include "music.h" //可选,如果使用音乐播放功能 #include "ADC.h" //可选,如果使用ADC模块(含EXT上ADC) #include "uart2.h" //可选,如果使用串口2通信(485通信、或EXT上串口) code unsigned long SysClock=11059200; //必须。定义系统工作时钟频率(Hz),用户必须修改成与实际工作频率(下载时选择的)一致 #ifdef _displayer_H_ //显示模块选用时必须。(数码管显示译码表,用戶可修改、增加等) //******* 用户程序段2:用户自定义函数声明 *************// #ifdef _displayer_H_ //显示模块选用时必须。(数码管显示译码表,用戶可修改、增加等) code char decode_table[]={ 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x08,0x40,0x01, 0x41, 0x48, /* 序号: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ /* 显示: 0 1 2 3 4 5 6 7 8 9 (无) 下- 中- 上- 上中- 中下- */ 0x3f|0x80,0x06|0x80,0x5b|0x80,0x4f|0x80,0x66|0x80,0x6d|0x80,0x7d|0x80,0x07|0x80,0x7f|0x80,0x6f|0x80, /* 带小数点 0 1 2 3 4 5 6 7 8 9 */ 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,~0xbf,~0xdf,~0xef,~0xf7,~0xfb,~0xfd,~0xfe}; //******* 用户程序段3:用户程序全局变量定义 *************// #include "song.c" //举例。song.c中编写了音乐(歌唱祖国)编码 unsigned char d[8] = { 33, 0, 0, 0, 0, 0, 0, 0}; int score1 = 0, score2 = 0; char format, flag, fin, flag2, diff = 1; //0 alone 1 togater 0 start 1 end unsigned char OK = 1, OK2 = 1; //联机模式判断是否挂了 1没挂 0挂了 //flag2 0 处于发题阶段 1处于游戏阶段 char disp = 26; unsigned char datao[7]; //举例。通信(串口1、串口2、红外共用)缓冲区8字节 unsigned char datahead[2] = { 0xaa, 0x55}; //校验位 char loc = 7, val7 = 26, val6 = 1; int time = 0; int delay = 100; char normal = 0; //0 正常接送状态 1 异常接受状态 char First=1; void updatadisp() //显示更新函数 { Seg7Print(d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7]); } void PlayGame() //玩游戏 { int mid = score1; int i; if (flag == 1) //游戏结束阶段 { for (i = 0; i < 7; i++) { d[7 - i] = (char)(mid % 10); mid = mid / 10; } } if (flag == 0) { for (i = 1; i < 8; i++) d[i] = 10; d[loc] = disp; if (loc == 1) { if (d[0] + disp == 65) { score1++; loc = 7; disp = rand() % 7 + 26; } else { SetBeep(2000, 50); flag = 1; fin = 1; } } else { loc--; } } } void PlayGameTogater() { int i, mid; if (flag2 == 0) //双方发题阶段 { mid = score1; for (i = 0; i < 4; i++) { d[3 - i] = (char)(mid % 10); mid = mid / 10; } d[4] = 10; d[5] = 10; d[6] = val6; d[7] = val7; if (OK == 0 && OK2 == 0) { if (score1 >= score2) { SetMusic(enumModeInvalid, enumModeInvalid, &song, sizeof(song), enumMscDrvLed); SetPlayerMode(enumModePlay); } OK = 1; First=1; } } else //游戏阶段跑动中需要添加延时 { SetPlayerMode(enumModeStop); LedPrint(0); for (i = 1; i < 8; i++) d[i] = 10; d[loc] = disp; if (loc == 1) { loc = 7; if (d[0] + disp == 65) { OK = 1; if (diff <= 5) score1 += diff; else if (diff <= 8) score1 += diff * 2; else score1 += diff * 3; } else { OK = 0; SetBeep(2000, 50); datao[0] = 0xaa; //校验码0xaa,0x55 datao[1] = 0x55; datao[2] = d[6]; datao[3] = d[7]; datao[4] = score1; datao[5] = OK; datao[6] = 1; //异常发送 Uart2Print(&datao, sizeof(datao)); } flag2 = 0; } else loc--; } } void Play_callback() //游戏回调函数 { if (format == 0) { if (flag == 0) { time++; if (time == delay) { PlayGame(); time = 0; if (score1 < 5) delay = 100; else if (score1 < 10) delay = 80; else if (score1 <