总结:代码思路

总结:

实验1:点LED灯

  1. LED端口的定义,也可直接使用头文件里的,LED灯P2口低电平点亮
  2. 用STC-ISP生成延时函数
  3. 左移函数和右移函数的使用,循环移位只需加上for循环
_crol_()左移函数,第一个参数是需要左移的地址,第二个参数是左移的位数
_cror_()右移函数,第一个参数是需要右移的地址,第二个参数是右移的位数

实验2:蜂鸣器 按键提示音

beep.c:位定义蜂鸣器的端口P1^5,一个延时函数,一个蜂鸣器发出响声的函数,在for循环里不断翻转蜂鸣器电平,并加上延时,使其有周期性

Delay.c:1ms延时函数

key.c:软件消抖方式的按键检测

Nixie.c:数码管显示,先位定义好74HC138译码器的三个引脚P22、P23、P24,8种组合对应数码管的位选,再用数组定义好P0口所需的段选数值,显示的函数里用switch case 判断参数传来的位选以及段选

main.c:获取按键值,有按键按下则蜂鸣器发出响声,数目管显示按键值

实验3:静态数码管

main.c:P22,P23,P24三个引脚组成位选,P0口是段选,段选的哪一位给高电平,哪一位就亮

实验4:动态数码管

main.c:根据人的视觉暂留现象,用for循环将每一位都依次点亮,最后加上延时,延时短则所有位都亮,延时长则一位一位点亮,延时后面要加上消影操作,即位选P0口全置0

实验5.:独立按键(二进制)

main.c:定义一个局部变量NUM,当有按键按下时,NUM就++,把NUM取反后赋给端口P2,因为LED要为0才亮,NUM每按一次加1

实验6:矩阵按键(LCD显示)

矩阵键盘扫描(输入扫描)
原理:读取第1行(列)→读取第2行(列) →读取第3行(列) → ……,然后快速循环这个过程,最终实现所有按键同时检测的效果

matrixkey.c:先将P1口全部置1,然后P13脚置0,则第一列右边已经是低电平了,就分别去判断P17、P16、P15、P14是否被按下,即判断P17~P14是否是0,是则按键按下,函数返回对应的键码值,复制三份,修改对应的引脚,即每一列都要判断

main.c:主函数读取键码值,并在LCD上显示

在这里插入图片描述

实验6:矩阵按键(LCD显示)-密码锁

matrixkey.c:用上一个代码的矩阵按键检测方法

main.c:主函数中获取到键码值后,进行判断,键码值要小于10,一个密码为4位,定义一个count全局变量,每次按一个0~9的按键count就++,按下个位后,第二次按时原来的个位就变成了十位,新按的值加入个位,再按一次十位就进到了百位;接下来就通过判断是否按下key11确认键,然后判断输入的密码跟写死的密码是否相等,相等就在LCD右上角显示OK,错误则显示ERR,对和错密码都清零,以便重新输入,按key12清除键则密码清零,重新输入

if(count < 4)
{
    password *= 10;			//原来的数*10,向高位移一位,最低位为0
    password += ret%10;		//最低位加上新按下的密码值,%10是保证ret的值是0~9
    count++;				//控制次数,密码只有四位
}

实验6:矩阵按键(LCD显示)升级密码锁

matrixkey.c:用上一个代码的矩阵按键检测方法

mian.c:跟密码锁代码逻辑差不多,这个加了自己设置密码的功能 ,首次开启会提示输入密码,按下key1,输入密码,中间判断跟上个代码一致,最后按确认键保存,然后输入密码,判断一样,如果密码跟自己设的不一样,则ERR,如果一样就OK

实验7:8x8点阵显示一个图形

main.c:定义74HC595芯片要用到的引脚,先定义一个函数用来实现74HC595(串转并)芯片的功能,用字模工具生成要显示图形的十六进制数据,用数组存着,再写个显示图形的函数,参数column控制列,dat控制行数据,因为P0口是给低电平才亮,所以把列&0x80取反后给P0,函数里要作消隐操作,即P0口置1;最后在mian函数中用for循环,不断给P0口的每一列置0,进行快速扫描,i控制的是列,因为行的数据已经通过字模软件生成了,只要在i列的时候显示这一列的哪一行要亮,根据人眼余晖暂留,就可看到一个图形

实验7:8x8点阵动态显示?

main.c:其余代码跟显示一个图形的一样,不同的是main函数里面,for循环扫描P0口时,行的数据是[i+offset],即列号加上偏移量,后面用count++控制offset++,offset++后还要注意不能数组溢出,不太懂

实验8:外部中断

main.c:先定义外部中断所使用的引脚,外部中断0是P3_2口,外部中断1是P3_3口,而P3_2、P3_3刚好是KEY3、KEY4的引脚,所以平时没配置外部中断开启时使用的是普通IO口的功能,在中断配置函数中,EX0 = 1让外部中断0开启中断,EA = 1开启总中断,IT0 = 1为下降沿触发,IT0 = 0则为低电平触发;然后在中断处理函数中处理外部中断,当KEY3不按下时是高电平,按下则为低电平,产生了下降沿,就进入了中断,中断处理函数中可以让LED灯翻转,要注意中断号一定要写对,外部中断0中断号是0

实验9:定时器中断

main.c:定义配置定时器0的函数,配置TMOD,一般会用TMOD &= 0xF0将低位清0,高位保持不变,然后设置定时器的工作方式,TH0,TL0赋初值,设置计数多少后爆表产生中断,计数到65536溢出,ET0 = 1,EA =1,开启中断;在中断处理函数中,TH0和TL0溢出会硬件置0,要将TH0和TL0重新赋值,为下一次的计数作准备,可以再定义一个局部变量count,当每计数1ms时进一次中断,count++,累加到1000次则经过了1s,则可以执行其他代码,实现了精准定时;记得在main函数中调用初始化函数

定时器计时溢出后不一定非要用中断来处理,定时和中断可以分开使用的,在配置定时器函数中不开启中断,则可以在主函数中将TH0和TL0重新赋值,也可以使count++,只不过这样是用CPU来处理,在中断处理函数中处理则效率高,有多线程的意思,main函数执行主要功能,定时器中断执行次要功能

实验9:定时器控制流水灯

main.c:配置定时器函数跟上面一样,可以用STC-ISP一键生成,开启中断,在中断处理函数中将TH0和TL0重新赋值,count++,定义一个变量mode,mode = 1则用左移函数 _crol _()左移P0端口,mode = 0则用右移函数 _cror _()右移P0端口,每次移一位;在main函数中检测按键key1,key2是否按下,key1按下则mode = 0,key2按下则mode = 1

实验9:定时器-时钟

time.c:先定义秒、分、时三个全局变量,然后定时器0配置,配置为1ms,开启中断,在中断处理函数中,TH0和TL0重新赋值,令count++,当count>1000时,秒++,当秒>59时,分++,当分>59时,时++,当时>23时,全部清零,重新开始计时,main函数中,初始化定时器0,初始化LCD1602,在while循环里分别在屏幕的合适位置上显示时、分、秒

实验10:串口通信

usart.c:先配置串口初始化函数,设置T1定时器为定时模式,工作方式为2:8位自动重装定时器,可用STC-ISP的波特率设置生成初始化函数,打开串口中断和总中断;在中断处理函数中,串行口中断号为4,定义局部变量接收SBUF的值,然后将接收中断标志RI置0,等待下一次接收数据,可以再将变量接收到的串口数据赋给SBUF,while(!TI),当没发送完成时,TI=0,!TI=1,此时不会退出循环,发送完成后TI=1,!TI=0,会退出循环,然后也要手动将TI置0,为下一次发送作准备;最后只需在main函数中调用串口配置函数即可完成电脑串口发送信息到单片机,触发中断单片机再将信息发回给电脑

实验10:串口通信 串口向电脑发送数据

usart.c:配置串口初始化函数,开启串口中断,定义一个1ms的延时函数,然后定义一个单片机串口发送数据的函数,参数为要发送的数据,在函数里将参数放到SBUF上,while(TI == 0),TI = 0,最后在main函数中先定义一个count = 0,while循环前调用函数发送数据0x66,延时两秒,在while循环内调用函数发送0x77,延时两秒,count++,当count >5时count清零,用break跳出循环,串口助手看到的现象是单片机先发送66,隔两秒后发送77,发送6个77,然后再发送66;后面实验直接把while循环注释掉,单片机就一直发送66

可得出结论:单片机是不断循环执行main函数的,就算没有加while循环,也是重复执行主函数,而为什么一般要加上while循环

网上答案一:我们在单片机中使用while(1),大部分还是为了防止程序跑飞,因为很多时候执行完某段程序后单片机的程序指针PC(就是程序指针)并不会停止,仍然会继续从ROM中读取指令并执行,这样一来可能会出现程序跑飞的情况,进而出现不确定的结果,我们加个while(1)就能让程序在执行完后在原地循环,相当于停在原地,防止跑飞。

网上答案二:下载到单片机运行的程序包含两部分,一部分是我们编写的程序代码,另外一部分是编译器自动生成的代码,因此,用KEIL软件编写的程序在没有while(1)的情况下运行到最后一行,会自动跳转到main函数第一行运行。通过查看一个简单P2_1口置0的程序的汇编代码发现汇编代码也是个循环,在main函数执行经过一大堆nop空指令后,会写着:C:0x000C 02000F LJMP main(C:000F)07 ;该汇编指令意思是重新跳到mian函数入口处执行;而在一开始创建工程时会提醒添加的51启动文件中,最后也有一句汇编代码: LJMP ?C_START,也是种跳转到开始的意思

这里的while(1)并不是防止程序“跑飞”的,而是防止main()返回。
①    在嵌入式中main是不能返回的。不同的C语言实现的单片机初始化代码会有不同的表现,有的是在call _main后jmp,而有的是jmp  0,等等这些会导致不可预料的结果。
②    在我们写的C语言后转换成汇编,再观察单片机的代码区,你会发现没有写程序的部分例如全1或者全0区域,程序运行到这里,就会有可能造成意料不到的结果。若无while1)循环,程序全部执行后,跳转至程序起始处重新执行。

实验10:串口通信 电脑发送数据控制LED

usart.c:配置串口初始化函数,这里用的波特率是9600,定义串口发送函数,将参数放到SBUF上,在中断处理函数种中,定义变量接收SBUF的值,将变量取反后赋给P2端口,根据接收到的数据将LED灯点亮,调用发送函数同时将接收到的数据再发送到电脑上显示,main函数中调用串口初始化函数

实验13:DS1302时钟

DS1302.c:1.先位定义好时钟芯片的三个引脚IO、CE、SCLK

2.然后定义初始化函数DS1302_init(),将CE和SCLK置0

3.然后定义单字节写数据函数DS1302_WriteByte(unsigned char command,unsigned char Data),一个参数是命令字(是时分秒等时钟信息的地址),另一个参数是数据,函数里按照DS1302的时序编写,先发送命令字,再发送数据,相当于先给定要写入的时钟信息,再写入数据;

4.然后定义单字节读数据函数DS1302_ReadByte(unsigned char command),一个命令字参数,先发送命令字,再读取数据;

5.然后定义时间设置写入函数DS1302_SetTime(),通过调用写数据函数,将Data_Time数组中的十进制转为BCD码后写入到时钟芯片中

6.DS1302_GetTime()通过调用读数据函数,读到的时钟信息先从BCD码转为十进制,再放入到Get_Time数组中

7.main.c:主函数中调用DS1302的初始化函数,在while循环外DS1302_SetTime()设置时钟,在while循环里DS1302_GetTime()获取到时间信息,在LCD1602上显示

实验13:DS1302可调时钟-复杂

/**
  * 工程名:	可调时钟
  * 功能:		使用DS1302时钟芯片,在LCD1602上显示年月日,时分秒,星期,秒数自动增加
  *	控制说明:	key1按键控制显示时间或者设置时间
  *		  		key2按键控制要对哪一位进行设置
  *				key3按键控制对应位数值增加
  * 			key4按键控制对应位数值减少
  */

DS1302.c:跟上面的定义过程一样,在头文件中声明函数供主函数调用

Key.c:按键检测功能,软件消抖

Delay.c:1ms延时函数

Timer0.c:1ms定时器0初始化,主要是中断处理函数中每隔500ms翻转闪烁的标志位,当设置时间时选择哪一位则哪一位会闪烁显示,用空字符串挡住原来的时间信息即可,每500ms闪一次

main.c:TimeShow()在LCD上显示获取的时间,TimeSet()进入调整时间模式,key2按下选择设置的位,key3按下则对应位数值增加,key4按下则对应位数据减少,期间要判断年月日是否越界,每个大月小月,闰年和平年的2月,时分秒越界,自动进位减位,判断完进行闪烁设置,当对哪一位进行设置,&& 闪烁标志位是否等于1,为真则显示空字符串,为假则显示时钟信息,最后将获取时钟数据的数组每一位赋给设置时间的数组,在main函数中进行模式选择时可以重新设置时间;(获取时间数组可以不用,把获取的时间直接放到设置时间的数组里,比较简单)

实验13:DS1302可调时钟-简单,加星期

/**
  * 工程名:	可调时钟
  * 功能:		使用DS1302时钟芯片,在LCD1602上显示年月日,时分秒,星期,秒数自动增加
  *	控制说明:	key1按键控制显示时间或者设置时间
  *		  		key2按键控制要对哪一位进行设置
  *				key3按键控制对应位数值增加
  * 			key4按键控制对应位数值减少
  */

/**
  * 复杂的版本,有三处不足:
  * 1.将设置时间的数组和获取时间的数组分开,导致后续操作困难
  *	2.时钟加减越界的判断逻辑过多且不准确
  *	3.没有实现星期的加减功能
  * 
  * 该版本将对上诉问题进行优化
  */

DS1302.c:把设置时间Data_Time和获取时间Get_Time数组写成一个数组DS1302_Time,后续操作获取到的时间也放在该数组中,新增加星期的显示,先写入星期的命令字,再写入数据

main.c:大部分跟上个工程代码差不多,改为一个数组后,在闪烁判断后不需要将获取到的时间再次赋值给设置数组,直接对原时间数组进行操作,加上对星期的增加减少和越界判断

实验15:IIC总线

I2C.c:先位定义SCL、SDA引脚,起始信号I2C_Start(),停止信号I2C_Stop(),发送一个字节I2C_SendByte(unsigned char dat),接收一个字节I2C_ReceiveByte(),发送应答I2C_SendAck(unsigned char ack),接收应答I2C_ReceiveAck(),各函数按照时序图编写SCL、SDA引脚的高低电平

AT24C02.c:发送一帧数据AT24C02_SendData(unsigned char word_address,unsigned char dat),word_address为要往哪个字地址发送数据,dat为要发送的数据,接收一帧数据AT24C02_ReceiveData(unsigned char word_address),word_address为从哪个地址接收数据,根据AT24C02的时序编写发送和接收数据的具体过程

main.c:按键1按下Data++,按键2按下Data–,LCD会相应显示,按键3按下则写入到AT24C02中,因为一个字最多存255,超过的会舍弃高位的,所以要将数据的高8位和低8位分别保存在两个地址中,按键4按下则读取出来,先读低位的数据,然后将读取到的高位数据左移8位后或上低位数据,就组成了一个完成的数据,最后在LCD上显示

实验16:秒表(定时器扫描按键数码管)

key.c:Key_GetState()按键检测函数,一但有按键被按下,标志位keynum立即置位并返回,给key_loop函数处理,没有用到Delay延时和while()判断松手

key_loop()每隔20毫秒执行一次该函数,对按键状态进行扫描,获取从Key_GetState()返回的按键值,定义上次状态的变量和本次状态的变量,如果上次不为0而本次为0则表示按键被按下,如果上次为0而本次为1则表示按键松开,在判断后将key_keyNumber标志位赋按键值,在key_return()函数中用temp接收一下,将temp返回给主函数调用

main.c:调用定时器的初始化函数,中断处理函数中时间定为20ms,每隔20ms执行一次key_loop()函数,不断扫描按键

数码管定时器扫描未见到效果

实验17:DS18B20温度显示

OneWire.c:因为DS18B20是用单总线通信的,所以要先把但总线的时序写好,OneWire_Init()单总线初始化,OneWier_SendBit(unsigned char Bit)主机发送一位,OneWire_ReceiveBit()主机接收一位,OneWire_SendByte(unsigned char Data)发送一个字节,即调用发送一位的函数8次即可,OneWire_ReceiveByte()接收一个字节,即调用接收一位的函数8次

DS18B20.c:DS18B20_ConvertT(void)DS18B20温度转换,即将温度传感器的值读入到RAM中,要在函数内使用OneWire_SendByte发送特定的地址,DS18B20_ReadT()读取温度供main函数使用,要注意BIT3~0是小数位,最后结果要除以16.0才正确数值,并保留小数

main.c:main函数中先调用温度转换函数DS18B20_ConvertT,将温度值读入到DS18B290的RAM中,并延时一会,消掉默认的温度值,在while中也要进行温度转换,然后用DS18B20_ReadT将温度读取出来,赋给一个变量,然后在LCD上显示,小数部分要单独取出来显示,如果是4位小数,方法是先乘以10000,强转为unsigned long型,然后再%10000,取出小数部分,与整数分开显示

实验17:DS18B20 温度报警器

key.c:定时器动态扫描按键

Timer0.c:定时器0初始化,中断处理函数用于按键扫描

AT24C02.c:main函数中用于将阈值存入AT24C02中,传输用到了I2C协议

DS18B20.c:获取温度传感器的值

main.c:先初始化LCD,定时器,温度转换,while循环中先温度转换,读取温度值,在LCD上显示,定义两个全局变量表示高阈值和低阈值,按键1高阈值++,按键2高阈值–,按键3低阈值++,按键4高阈值–,在增减中也要加上判断,如高阈值不能超过125,低阈值不能低于-55,高阈值不能低于低阈值,低阈值不能高于高阈值,如果相等了,再增加或者减少的话就–,阈值也时刻显示在LCD上,然后调用AT24C02_SendData(0,Tlow);和AT24C02_SendData(1,Thight);将阈值写入到EEPROM中保存;如果检测到的温度超过或低于阈值,则在LCD右上角显示过高或过低的标志,并将蜂鸣器的标志位置1,蜂鸣器报警;然后在main函数开头处写Tlow = AT24C02_ReceiveData(0);
Thight = AT24C02_ReceiveData(1);读取AT24C02中的阈值,如果一开始没有数据则赋初值,显示在LCD上

实验18:LCD1602

LCD1602.c:先位定义LCD的WR、RS、EN引脚,宏定义P0口,

LCD_WriteCommand(unsigned char Command)LCD1602写指令,

LCD_WriteData(unsigned char Data)LCD1602写数据,

LCD_Init()LCD1602初始化,初始化要调用LCD_WriteCommand函数写入4个配置LCD显示的指令,

LCD_SetCursor(unsigned char Line,unsigned char Column)LCD1602设置光标位置,因为无论显示什么类型数据都要先设置光标位置,即在哪个位置显示,所以提取出来写成一个函数调用,

LCD_ShowChar(unsigned char Line,unsigned char Column,unsigned char Data)LCD1602在指定位置上显示一个字符,

LCD_ShowString(unsigned char Line,unsigned char Column,char *string)LCD1602在指定位置上显示字符串,

LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int number,unsigned char length)LCD1602在指定位置上显示十进制数字,Pow(int x,int y)求x的y次方,因为要将整型数的每一位都提取出来,再转为字符才能显示,所以求次方函数使用来提取每一位的,

LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int number,unsigned char length)LCD1602在指定位置上显示有符号十进制数字,跟显示整型数据差不多,只不过要加上正负号显示

LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int number,unsigned char length)LCD1602在指定位置上显示十六进制数字,只是将整数提取位数时/10和%10改为/16和%16

LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int number,unsigned char length)LCD1602在指定位置上显示二进制数字,将整数提取位数时/10和%10改为/2和%2

main.c:在main函数中先要调用LCD初始化函数,然后才能调用相应函数显示字符;如果想显示字符滚动效果,则需在屏幕外面的地址写入字符串,然后在while循环内调用写命令的函数LCD_WriteCommand(0x18);写入指令后并延时Delay1ms(500);就能实现屏幕滚动的效果

实验19:LED呼吸灯

main.c:主要使用for循环控制变量time从0到100变化,作为高低电平的持续时间,里面一层for循环主要是控制有多少个这样的周期,LED亮后延时的时间是time,灭后延时的时间是100-time,所以亮和灭的总时间是100,可以实现从不亮慢慢到亮的效果,如果想从亮到灭,只需复制一遍循环,把time从100减到0即可

实验20:PWM控制电机速度

key.c:定时器0中断扫描按键

Timer0.c:定时器0的初始化函数,定时值为100us

main.c:定义电机的端口P1^0,一个计数值全局变量,一个比较全局变量,main函数中调用初始化函数,然后检测按键的返回值,通过不同的按键改变比较值的值, 中断处理函数中,TH0和TL0重新赋值,count++,count%=100将count的范围设为0~99,调用key_loop函数,然后判断计数值count和比较值compare的大小,如果count小于compare,则电机端口置1,如果count大于compare,则电机端口置0

实验21:AD转换

XPT2046.c:先定义端口DIN、CS、DCLK、DOUT,XPT2046_ReadAD(unsigned char Command)ZPT2046读取AD值,参数是命令字,在.h头文件中宏定义好的命令字,按照XPT2046的时序,先初始换时钟,然后开始发送指令,for循环8次,从高位开始发送指令,时钟线给上升沿则发送数据,然后读取数据,for循环16次,先跳过时序图中BUSY高电平的部分,来到读取开始的时序,读取数据到变量中,返回数字量,将命令字的MODE位取出来判断,当MODE位是1时,选择8位为转换分辨率,所以要左移8位得到真实数值同时返回,当MODE位是0时,选择12位为转换分辨率,16-12=4,就左移4位得到数据同时返回,MODE位取值要在宏定义地址时区分开来

main.c:先LCD初始化,在while循环内调用XPT2046_ReadAD函数,对照手册的表,XP、YP、VBAT、AUX要读取哪一个,就将地址组合好后放到参数中,应事先在XPT2046.h头文件中宏定义好,用全局变量接收函数返回的值,然后显示在LCD上

实验22:DA转换(PWM)

main.c:DA转换实际就是PWM,可以用PWM来代替,所以平时DA转换用的少,程序现象:DAC模块的DA1灯呈呼吸灯状态,先定义计数值和比较值,在main函数中一个for循环i从0~99,将i赋给比较值compare,时刻改变compare的值,另一个for循环i从100减到1,也赋给比较值,在定时器中断处理函数中,TH0和TL0重新赋值,count取值范围0到99,如果count小于compare,则DA1灯置1,如果count大于compare,则DA1灯置0

实验23:红外遥控

Int0.c:外部中断0初始化,选择下降沿触发

Timer0.c:定时器0初始化,TH0和TL0初始化为0,清除TF0标志,TR0停止计时;另外定义函数设置计数器值Timer0_SetCounter(unsigned int value),分别为TH0和TL0赋初值,value的高位放TH0,低位放TL0,TH0 = value/256;TL0 = values%256;Timer0_GetCounter()获取计数器值,Timer0_Run(unsigned char Flag)定时器0启动停止控制,参数为0停止,为1开始

IR.c:IR_Init()红外遥控初始化,初始化外部中断0和定时器0,IR_GetDataFlag()红外遥控获取收到数据帧标志位,IR_GetRepeatFlag()红外遥控获取收到连发帧标志位,IR_GetAddress()红外遥控获取收到的地址数据,IR_GetCommand()红外遥控获取收到的命令数据,在下降沿触发的外部中断0处理函数中对数据进行接收

main.c:while循环中判断IR_GetDataFlag || IR_GetRepeatFlag是否为真,为真用变量Address接收IR_GetAddress()返回的地址值,变量Command接收IR_GetCommand()返回的指令,在LCD上显示,如果指令等于IR_VOL_MINUS则表示按下遥控器的VOL–键,则NUM–,在LCD上显示,如果指令等于IR_VOL_ADD则表示按下遥控器的VOL++键,NUM++并显示,按下的话在LCD上显示就是一直变化的

实验23:红外遥控 控制电机速度

Timer1.c:定时器1用于电机的PWM调速

Timer0.c:定时器0用于红外接收信号时计算时间

Motor.c:将电机的PWM调速写成一个.c文件,先定义电机的端口,然后Motor_Init()电机初始化,就是初始化定时器1,Motor_SetSpeed(unsigned char Speed)设置电机速度,将参数Speed赋给比较值Compare,在定时器1中断处理函数中,TH0和TL0重新赋值,count++的范围是0到99,比较count和compare的大小

IR.c:和上一个工程一样

Int0.c:和上一个工程一样

main.c:while循环中判断如果收到数据帧IR_GetDataFlag(),if判断如果为真,则Command = IR_GetCommand(),判断Command是0、1、2、3哪个按钮按下的,按钮有对应的按键码,可在头文件处宏定义出来,方便使用,则在判断后调用Motor_SetSpeed(50)函数设置电机的比较值,即转速

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我了解了。首先,我们需要将八段数码管的8个LED分别连接到单片机的8个I/O口上,这样我们就能通过I/O口控制数码管的显示了。 接下来,我们需要使用独立按键来控制数码管的显示。一般来说,我们可以使用一个外部中断来检测按键的状态,当按键被按下时,中断程序会被触发,从而改变数码管的显示。以下是一个简单的程序示例: ```assembly ; 定义I/O口和按键的引脚号 PORT_DATA equ P1 ; 数据口 PORT_CTRL equ P2 ; 控制口 KEY1 equ P3.2 ; 按键1 ; 定义数码管显示的数据 DIGITS db 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F ; 中断服务程序 ISR: push ACC ; 保存ACC寄存器 mov ACC, #0 ; 初始化ACC寄存器 mov A, KEY1 ; 读取按键状态 cjne A, #0, KEY_PRESSED ; 如果按键被按下,则跳转到KEY_PRESSED标签 pop ACC ; 恢复ACC寄存器 reti ; 返回中断 ; 按键被按下后的处理程序 KEY_PRESSED: mov A, PORT_DATA ; 读取数据口的值 inc A ; 将数码管的值加1 cjne A, #10, NORMAL_DISPLAY ; 如果数码管的值小于10,则跳转到NORMAL_DISPLAY标签 mov A, #0 ; 如果数码管的值等于10,则将其置为0 mov PORT_CTRL, #0x08 ; 在数码管的第一个位上显示“1” sjmp END_DISPLAY ; 跳转到END_DISPLAY标签 ; 正常的数码管显示程序 NORMAL_DISPLAY: mov PORT_CTRL, #0x04 ; 在数码管的第二个位上显示“0” mov DPH, #DIGITS ; 将数码管显示的数据存入DPH寄存器 mov DPL, A ; 将数码管的值存入DPL寄存器 movx A, @DPTR ; 通过DPTR寄存器将数据写入数据口 inc DPTR ; DPTR寄存器自增1 mov PORT_CTRL, #0x02 ; 在数码管的第三个位上显示“0” mov DPH, #DIGITS ; 将数码管显示的数据存入DPH寄存器 mov DPL, A ; 将数码管的值存入DPL寄存器 movx A, @DPTR ; 通过DPTR寄存器将数据写入数据口 inc DPTR ; DPTR寄存器自增1 mov PORT_CTRL, #0x01 ; 在数码管的第四个位上显示“0” ; 数码管显示结束 END_DISPLAY: pop ACC ; 恢复ACC寄存器 reti ; 返回中断 ``` 以上代码仅供参考,实际上还需要根据具体的硬件电路和需求进行修改。希望能对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值