文章导航
大三上电子线路设计上实验报告3
——单片机播放《bad apple》动画(带延时功能)
一、硬件原理图
(一)数码管
我采用的是7SEG-MPX2-CA型两位数字显示的数码管,可以显示0~99一共100个数字,由ABCDEFG DP八个输入控制,其电位分别由单片机的P3.0~P3.7接出,并行受到单片机的控制。1,2端分别接Q1,Q2两个晶体管和电源作为驱动。两个晶体管的控制信号分别由单片机的P2.6、P2.7口接出。在与老师的交流中我了解到,虽然仿真时不接驱动也可以实现,但是在实际操作中,外加驱动是必不可少的,单片机只能提供控制信号,而数码管的能量要靠驱动获得。
(二)Lcd显示屏
Lcd 显示屏由128x64个像素组成,型号为AMPIRE128x64。Lcd显示屏的8,7,6,2,1口分别接单片机的P2.0~P2.4口;9~16口分别接单片机的P1.0~P1.7口;17口接电源。由单片机产生并行信号把图片显示在屏幕上,经过设定显示的内容、延时等等,就可以实现动画效果。
在老师的例程中,我探究如何把图片转换为像素文件,在Image2Lcd软件中,将比例为128x64比例的图片导入,但是最开始,我的图片显示出现了问题,呈现一种多个图片重复叠加的效果,在尝试之后发现应当把扫描方式改为数据水平,字节垂直;下面勾选“字节内象素数据反向”。最后呈现的结果如下图所示:
(三)键盘
键盘用五个可复位按键开关组成,分别用于实现倒计时复位/视频暂停、倒计时开始/视频重新播放、停止计时、计时加一、计时减一的功能。其中第一个按键接单片机的P2.5口,第二~第五分别接单片机的P1.4~P1.7口,用于输入控制信号。
(四)SD卡模拟器
这是一个SD卡模拟器MMC,可以模拟外接的存储卡。其中的内容由SD.mmc提供。由于视频数据比较大而单片机的空间有限,只需要在播放时从外部读取每一帧的数据即可,该元件就是实现了这个功能。其CLK、DO、DI、CS口分别接单片机的P1.0~P1.3口,用于输入数据。
(五)时钟电路
单片机必备的计时电路,由晶振、电容等等元件组成,生成时钟信号,分别接单片机的XTAL1、XTAL2、EA口。
(六)单片机AT89C52
电路中最重要的器件,本实验中采用AT89C52单片机,其中引脚与外部的连接在前面已经介绍,在本例中的主要作用是依据键盘输入的信号,控制数码管和lcd显示屏输出内容。包括开始计时、暂停计时、计时数增减、暂停播放视频、从头播放视频等等。其中MMC、键盘、时钟是输入信号,lcd、数码管是输出设备。
二、软件实现流程
(一)主函数部分main.c
主要利用了计时当中key()函数中全局变量jishu、bz的变化,在播放动画时,若键盘有输入,jishu的值也会变化,此时通过条件语句判断,如果jishu不为0,跳出循环(暂停)。若bz为1,播放动画的帧序号变量SD_ADDR置零,实现重复播放。 播放动画部分 主要函数为dispicture、dispictureb、SdReadBlock 作用分别是:显示LCD上半部分、显示LCD下半部分、读取SD卡文件。 其中SdReadBlock函数在文件SD.c中,SD.c为从网上搜索的读取SD卡方法的例程,在研究清楚其具体作用后,我将它放入了自己的工程中,并进行了调用。
倒计时部分 主要函数为display()、dis()、key() 分别的作用是:获取数码管显示的数字信息、进行数码管显示、读取按键内容。
可以看出,key()函数的主要作用就是通过读入按键的信息,改变全局变量的值,在数码管例程中,它的作用是改变数码管的值,那么我也可以把它们应用到动画播放当中,从而实现动画播放当中的控制,包括暂停,重播等等。与倒计时配合,可以达到预期效果。
(二)SD卡读取数据部分SD.c
此部分为例程引用,是一个单独的部分,对于它的功能进行了探究,它的作用是从SD卡中读取数据,并且通过四根引线传入单片机当中。
(三)头文件SD.h
起初考虑过把所有的内容都放到一个c文件当中,但是考虑到程序的可读性和修改的方便,同时为了区分我的工作内容和外部引用,我把它们分了开来。其实多个代码文件构成一个工程,共同实现一个功能,这是所有单片机开发者必须学会的操作。我借此练习了一下多个程序文件之间连接调用的方法。通过查阅资料,我了解到,正如学习C语言是要用到的头文件,我也可以自己定义一个头文件,这样就可以实现外部的函数引用。
刚开始我的程序报错了,原因是没有在外部引用的c文件中也包含该头文件,在修改以后就实现了外部库函数的调用。
视频见:“计时播放视频.mp4”工程文件见“lib3”文件夹
三、实验总结
通过这半个学期的电子线路设计实验,我着实学到了许多。忽然想到一句话:“纸上得来终觉浅,绝知此事要躬行”。在课堂上学到的东西很多,但是大部分如果不用的话很快就会忘记,但是这个实验中学到的许多知识却是记忆犹新。 有许多操作,许多电子线路、数字逻辑、单片机原理、接口技术等等的知识,虽然以前在课堂上学过,但是却不太记得。在调试实验电路时,我遇到问题,会从网上论坛、课本等等渠道去寻求解答。在实在解决不了问题时,我会和同学老师讨论。在这样的氛围下,我把之前不会的、不扎实的知识又重新学习巩固了一遍。 让我印象深刻的是第二次实验,我做了一个放烟花的电路,其中控制电路用到了晶体管。虽然模拟电子技术当中反反复复的学过,但是真正应用的时候,还是又这样那样的问题。遇到了二极管不亮的情况,返回去排查电路,应用模电知识,我发现是晶体管工作在了截至区的缘故。 还有就是在应用Image2Lcd软件时,刚开始显示的图片是重叠的。经过探索,我发现是扫描方式没有选对。这样经过探究错误、发现问题、解决问题的过程,让我对于像素表示图像的原理有了一定的认识。 最后一次实验也是我一直想做的,之前看到b站好多大佬用单片机播放bad apple动画,我都很羡慕,期望有一天能自己实现。现在在仿真软件上勉强实现了一下,还加入了一些小功能。不过其中很大一部分代码不是我的原创,是从各种例程当中改过来的。当然,实际的芯片和仿真软件也会有差别,所以说我要做的还有很多,在即将到来的嵌入式实验中,我可以进一步在实体芯片上再次尝试实现播放bad apple。 在应用单片机时,并行、串行、总线等概念时时出现,这些内容也在微机原理与嵌入式系统的课程中反复出现,我要学的还有很多。虽然现在能实现一个简单的功能,但是我能感觉到自己对于这些概念的理解还有欠缺,所以在之后要再次进行深入的学习。 非常感谢老师的悉心指导!
四、做的不太成功的另一个作品
该部分实现结果不太理想,故没有放到正文中,不过还是把它写在报告里面。 视频文件见“another_播放速度控制.mp4”工程文件见“another”文件夹
原理图:
最大的不同就是加入了一个BCD码转七段数码管的元件7448.通过输入对应延时量的BCD码,改变动画播放延时的大小,从而控制动画播放的速度。
一些不同的器件 :
键盘:
PB0~PB3分别接单片机的P1.4~P1.7和7448的7、1、2、6口,输入的是需要延时的BCD码。
7448:
只是显示键盘输入BCD码的十进制表示,其实与单片机没有直接联系,本来我想通过单片机输出信号控制它,但是在播放动画的同时控制它会报错,查阅资料后发现加入一个锁存器会解决这一问题。
部分代码:
相交正式作品,这个比较简单,没有定时的部分,最后延时函数传入的参数是四位BCD码转换成的十进制数,从而实现了对延时的控制,进一步改变了播放速度。但是在仿真中,速度改变并不明显。
五、附录
(一)原理图
(二)程序代码
1)Main函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 #include <REGX52.H> #include "SD.h" #include <intrins.h> #define PP P3 unsigned char code SEG7[]={0xC0 ,0xF9 ,0xA4 ,0xB0 ,0x99 ,0x92 ,0x82 ,0xF8 ,0x80 ,0x90 ,};unsigned char num[]={1 ,2 };sbit q1=P2^6 ; sbit q2=P2^7 ; sbit k1=P2^5 ; sbit k2=P1^4 ; sbit k3=P1^5 ; sbit k4=P1^6 ; sbit k5=P1^7 ; unsigned long SD_ADDR=0 ;unsigned int count;unsigned char xdata DATA[512 ];sbit E = P2^0 ; sbit RW = P2^1 ; sbit RS = P2^2 ; sbit CS2 = P2^3 ; sbit CS1 = P2^4 ; #define DataPort P0 bit Chek_Busy (void ) { DataPort = 0xff ; RW = 1 ; RS = 0 ; E = 1 ; E = 0 ; return (bit)(DataPort & 0x80 ); } void Choose_12864 (unsigned char i) { switch (i) { case 0 : CS1 = 0 ;CS2 = 1 ;break ; case 1 : CS1 = 1 ;CS2 = 0 ;break ; case 2 : CS1 = 0 ;CS2 = 0 ;break ; default : break ; } } void LCD_Cmd (unsigned char cmd) { while (Chek_Busy()); RW = 0 ; RS = 0 ; DataPort = cmd; E = 1 ; E = 0 ; } unsigned char LCD_Read () { unsigned char read_data; while (Chek_Busy()); RW = 1 ; RS = 1 ; E = 1 ; E = 0 ; RW = 1 ; RS = 1 ; E = 1 ; read_data = DataPort; E = 0 ; return (read_data); } void LCD_Data (unsigned char dat) { while (Chek_Busy()); RW = 0 ; RS = 1 ; DataPort = dat; E = 1 ; E = 0 ; } void Set_PageY (unsigned char PAGE,unsigned char Y_Address) { LCD_Cmd(0xB8 + PAGE); LCD_Cmd(0x40 + Y_Address); } void LCD_Clear (void ) { unsigned char page,row; Choose_12864(2 ); for (page = 0xb8 ; page < 0xc0 ; page ++) { LCD_Cmd(page); LCD_Cmd(0x40 ); for (row = 0 ; row < 64 ; row ++) { LCD_Data(0x00 ); } } } void LCD_Init (void ) { CS2 = 0 ; CS1 = 0 ; LCD_Cmd(0x3F ); } void Dis_Picture (unsigned char *picture) { unsigned char ii,kk; for (kk = 0 ; kk < 4 ; kk ++) { Choose_12864(2 ); Set_PageY(kk,0 ); Choose_12864(0 ); for (ii = 0 ; ii < 128 ; ii ++) { LCD_Data(*picture); picture ++; if (ii == 63 ) { Choose_12864(1 ); } } } } void Dis_Pictureb (unsigned char *picture) { unsigned char ii,kk; for (kk = 4 ; kk < 8 ; kk ++) { Choose_12864(2 ); Set_PageY(kk,0 ); Choose_12864(0 ); for (ii = 0 ; ii < 128 ; ii ++) { LCD_Data(*picture); picture ++; if (ii == 63 ) { Choose_12864(1 ); } } } } void delayus (unsigned char t) { while (--t); } void delayms (unsigned char t) { while (t--) { delayus(245 ); delayus(245 ); } } void _delay_ms(unsigned int t){ unsigned int i,j; for (i=0 ;i<t;i++) for (j=0 ;j<120 ;j++); } void dis () { PP=num[0 ]; q1=1 ; _delay_ms(2 ); q1=0 ; PP=num[1 ]; q2=1 ; _delay_ms(2 ); q2=0 ; } unsigned int jishu1s=10 ;unsigned int jishu1=10 ;unsigned int jishu2;unsigned int bz;void dispaly () { num[0 ]=SEG7[jishu1%100 /10 ]; num[1 ]=SEG7[jishu1%10 ]; } void key () { if (k1==0 ){jishu1=jishu1s;while (k1==0 );} if (k2==0 ){bz=1 ;while (k2==0 );} if (k3==0 ){bz=0 ;while (k3==0 );} if (bz==0 ) { if (k4==0 ){if (jishu1s<99 )jishu1s=jishu1s+1 ;jishu1=jishu1s;while (k4==0 );} if (k5==0 ){if (jishu1s>0 )jishu1s=jishu1s-1 ;jishu1=jishu1s;while (k5==0 );} } } void main (void ) { _delay_ms(10 ); TMOD=0x01 ; ET0=1 ; TH0=(65536 -50000 )/256 ; TL0=(65536 -50000 )%256 ; TR0=1 ; EA=1 ; LCD_Init(); LCD_Clear(); SdInit(); DATA[0 ]=255 ;; DATA[1 ]=1 ; DATA[2 ]=2 ; DATA[3 ]=3 ; DATA[511 ]=0xf0 ; while (1 ) { dispaly(); dis(); key(); if (jishu1==0 ) { while (1 ) { while (!SdReadBlock(DATA,SD_ADDR,512 )); SD_ADDR+=512 ; Dis_Picture(DATA); while (!SdReadBlock(DATA,SD_ADDR,512 )); Dis_Pictureb(DATA); SD_ADDR+=512 ; delayms(100 ); key(); if (jishu1!=0 ) break ; if (bz==1 ) SD_ADDR=0 ; } } } } void Time0 () interrupt 1{ TH0=(65536 -50000 )/256 ; TL0=(65536 -50000 )%256 ; if (bz==1 ) { jishu2=jishu2+1 ; if (jishu2==20 ) { jishu2=0 ; if (jishu1>0 )jishu1=jishu1-1 ; if (jishu1==0 )bz=0 ; } } }
2)导入存储卡文件的SD.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 #include <REGX52.H> #include "SD.h" sbit ACC0=ACC^0 ; sbit ACC1=ACC^1 ; sbit ACC2=ACC^2 ; sbit ACC3=ACC^3 ; sbit ACC4=ACC^4 ; sbit ACC5=ACC^5 ; sbit ACC6=ACC^6 ; sbit ACC7=ACC^7 ; sbit SD_CLK = P1^0 ; sbit SD_DI = P1^2 ; sbit SD_DO = P1^1 ; sbit SD_CS = P1^3 ; void SdWrite (unsigned char DATA) { ACC=DATA; SD_CLK=0 ; SD_DI=ACC7; SD_CLK=1 ; SD_CLK=0 ; SD_DI=ACC6; SD_CLK=1 ; SD_CLK=0 ; SD_DI=ACC5; SD_CLK=1 ; SD_CLK=0 ; SD_DI=ACC4; SD_CLK=1 ; SD_CLK=0 ; SD_DI=ACC3; SD_CLK=1 ; SD_CLK=0 ; SD_DI=ACC2; SD_CLK=1 ; SD_CLK=0 ; SD_DI=ACC1; SD_CLK=1 ; SD_CLK=0 ; SD_DI=ACC0; SD_CLK=1 ; SD_DI=1 ; } unsigned char SdRead () { SD_CLK=0 ; SD_CLK=1 ; ACC7=SD_DO; SD_CLK=0 ; SD_CLK=1 ; ACC6=SD_DO; SD_CLK=0 ; SD_CLK=1 ; ACC5=SD_DO; SD_CLK=0 ; SD_CLK=1 ; ACC4=SD_DO; SD_CLK=0 ; SD_CLK=1 ; ACC3=SD_DO; SD_CLK=0 ; SD_CLK=1 ; ACC2=SD_DO; SD_CLK=0 ; SD_CLK=1 ; ACC1=SD_DO; SD_CLK=0 ; SD_CLK=1 ; ACC0=SD_DO; return ACC; } unsigned char SdResponse () { unsigned char i=0 ,response; while (i<=8 ) { response = SdRead(); if (response==0x00 ) break ; if (response==0x01 ) break ; i++; } return response; } void SdCommand (unsigned char command, unsigned long argument, unsigned char CRC) { SdWrite(command|0x40 ); SdWrite(((unsigned char *)&argument)[0 ]); SdWrite(((unsigned char *)&argument)[1 ]); SdWrite(((unsigned char *)&argument)[2 ]); SdWrite(((unsigned char *)&argument)[3 ]); SdWrite(CRC); } unsigned char SdInit (void ) { int delay=0 , trials=0 ; unsigned char i; unsigned char response=0x01 ; SD_CS=1 ; for (i=0 ;i<=9 ;i++) SdWrite(0xff ); SD_CS=0 ; SdCommand(0x00 ,0 ,0x95 ); response=SdResponse(); if (response!=0x01 ) { return 0 ; } while (response==0x01 ) { SD_CS=1 ; SdWrite(0xff ); SD_CS=0 ; SdCommand(0x01 ,0x00ffc000 ,0xff ); response=SdResponse(); } SD_CS=1 ; SdWrite(0xff ); return 1 ; } unsigned char SdWriteBlock (unsigned char *Block, unsigned long address,int len) { unsigned int count; unsigned char dataResp; SD_CS=0 ; SdCommand(0x18 ,address,0xff ); if (SdResponse()==00 ) { SdWrite(0xff ); SdWrite(0xff ); SdWrite(0xff ); SdWrite(0xfe ); for (count=0 ;count<len;count++) SdWrite(*Block++); for (;count<512 ;count++) SdWrite(0 ); SdWrite(0xff ); SdWrite(0xff ); dataResp=SdRead(); while (SdRead()==0 ); dataResp=dataResp&0x0f ; SD_CS=1 ; SdWrite(0xff ); if (dataResp==0x0b ) { return 0 ; } if (dataResp==0x05 ) return 1 ; return 0 ; } return 0 ; } unsigned char SdReadBlock (unsigned char *Block, unsigned long address,int len) { unsigned int count; SD_CS=0 ; SdCommand(0x11 ,address,0xff ); if (SdResponse()==00 ) { while (SdRead()!=0xfe ); for (count=0 ;count<len;count++) *Block++=SdRead(); for (;count<512 ;count++) SdRead(); SdRead(); SdRead(); SD_CS=1 ; SdRead(); return 1 ; } return 0 ; }
3)头文件SD.h
1 2 3 unsigned char SdInit (void ) ;unsigned char SdReadBlock (unsigned char *Block, unsigned long address,int len) ;unsigned char SdWriteBlock (unsigned char *Block, unsigned long address,int len) ;