单片机生产实习报告

生产实习

 


 


目录

1  设计任务... 1

1.1  基础项目... 1

1.1.1单片机最小系统... 1

1.1.2  简单外围电路制作与编程... 1

1.2 提高项目... 1

2  设计思路... 2

2.1  简单外围电路设计思路... 2

2.2  提高项目设计思路... 2

3  原理图... 2

3.1  基础项目原理图... 2

4  需要器件清单... 3

5  PCB图... 5

6  程序流程图... 5

6.1 基础项目流程图... 5

6.2 提高项目流程图... 7

7 编写的上位机界面... 8

8  程序代码... 8

8.1 基础项目的代码... 8

8.2 提高项目的代码... 14

9 心得体会... 18

10 参考文献... 18


1  设计任务

1.1  基础项目

1.1.1单片机最小系统

a)实验目的:熟悉简单的布线,元器件的辨认,焊接。单片机开发环境的安装与使用。

b)实验任务:按照给定电路原理图,进行单片机最小系统的焊接:包括单片机、开关、插排、复位电路和晶振电路,正确焊接后,电路可以进行程序的下载。

1.1.2  简单外围电路制作与编程

a)实验目的:熟悉简单的单片机外围电路的原理与设计;通过汇编或C 语言编写简单的单片机程序。

b)实验任务:设计并焊接简单外围电路,包括LED 与独立按键、蜂鸣器、双位数码管。使用汇编或C 语言编写程序,使本电路完成以下功能:LED 跑马灯、双位数码管对应计数,方式一(始终一个方向)、方式二(左右循环),可准确确定周期T。每次第一个LED 亮起的时候蜂鸣器响一声(t 秒)提示。一共三个按键分别实现以下功能暂停(检测该按键有效按下后,LED 和数码管暂停,再次检测按键按下后,继续执行当前循环)、复位(检测该按键有效按下后,LED 和数码管归零重新开始以当前模式循环)、模式转换(正常运行状态,检测该按键有效按下后,数码管显示不变,LED 显示从当前)。方式转换成另一方式继续执行。

1.2 提高项目

    所选提高项目为与上位机串口通信。

    核心器件:无

    功能描述:通过串口与上位PC 机进行双向通信。

检查方式:请指导教师检查。

要求:向老师说明电路设计功能,并进行展示。

2  设计思路

2.1  简单外围电路设计思路

外围电路主要包括:8个LED驱动电路、2P数码管驱动电路、3个按键电路、以及蜂鸣器驱动电路。由于51单片机的驱动能力弱,所以LED驱动电路选择了共阳的接法,把8个LED的阴极分别接到了P1的八个IO上;由于数码管是共阳的解法,我选择了数码管的8个段选接到的开漏的P0口,其2个位选通过2个NPN三极管S8050的开关作用进行控制,其2个控制端分别分配在了P2^6、P2^7引脚上;按键电路防止信号干扰,选择了上拉,由于有三个按键,单片机只有两个外部中断,模拟外部中断也挺麻烦,所以决定暂停播放的按键和模式切换的按键分配在了2个外部中断引脚P3^2、P3^3,另外一个接在了普通IOP2^0上;蜂鸣器采用的是有源蜂鸣器,所以电路同样采用了一个NPN的三极管S8050来驱动。

2.2  提高项目设计思路

  我们的提高项目选的是下位机与上位机通信,由于我们下载程序时已经焊接好了串口电路,所以提高项目的设计就不需要电路。

3  原理图

3.1  基础项目原理图

原理图我们使用Altium Designer 绘画,基础项目原理图如图3-1所示:

图3-1 基础项目原理图

4  需要器件清单

表4‐1 最小系统所需器件清单

表4‐2 简单外围电路所需器件清单

5  PCB图

以下是我们画的PCB图,如图5-1所示:由于我们是使用的洞洞板焊接电路,所以我们画的PCB布局也是对应9×15的洞洞板来设计和布线的。

图5-1 基础项目PCB

6  程序流程图

6.1 基础项目流程图

首先由流水灯、蜂鸣器、按键的检测、数码管显示如果都放在主函数里一直循环的话,势必会互相影响,所以我在设计的时候采用的思路是在定时器里进行跑马灯,蜂鸣器的鸣叫,在主函数里一直调用数码管显示函数,按键采用中断的方式,这样的互相就不干扰。假如定时器的定时时间为1s,即1s为基准。在第一秒的时候让第一个灯亮,第二秒的时候让第二个灯亮....,当到第九秒的时候判断时模式一还是模式二,再把相对应的灯的数据赋值个P1口,之后在模式一的时候当时间记到16S的时候,这时候清零计数,这样就形成了循环,同样对于模式二的时候当计到14的时候,这时候清零,这样也形成循环。这样就实现跑马灯的要求,周期也容易更改。播放和暂停的实现使用在外部中断里用一个变量进行计数,当计数为1时我们规定为暂停,计数为2时我们规定为播放,同时把计数清零以便形成循环。模式的操作同样也是采用这样的方法。在定时器里时间基准加一只有在播放模式下才加一,这样就实现了灯和数码管显示的暂停与播放。基础项目流程图如图6-1所示:

图6-1 基础项目流程图

6.2 提高项目流程图

上位机之间通信,我们采用双机通信方式,上位机给下位机发送的数据是不定长度的,且没指令后都加上帧尾ok。我么假设上位机给下位机发送的指令有:wok、wcok、wcyok。当下位机接收到wok时我们让第一个LED灯亮,并返回给上位机Command_wok;接收到wcok时第二个灯亮,并返回给上位机Command_wcok;接收到wcyok指令时让第三个灯亮, 并返回给上位机Command_wcyok。提高项目的流程图如图6-2所示:

 

图6-2 提高项目程序流程图

7 编写的上位机界面

     我们使用了VB编写了生产实习调试通信的上位机,界面如图7-1所示:

图7-1 上位机界面

8  程序代码

8.1 基础项目的代码

#include<reg52.h>

#define uint8_t unsigned char

#define uint16_t unsigned int

#define BeerOn beer = 1//打开蜂鸣器

#define BeerOff beer = 0//关闭蜂鸣器

sbit wei1 = P2^6;//数码管的个位控制端

sbit wei2 = P2^7;//数码管的十位控制端

sbit beer = P2^5;//蜂鸣器的控制端

sbit Rest = P2^0;//软件复位控制端

void delay(uint16_t DelayTime);//简单的延时函数

void display(uint8_t dis_data);//数码管显示函数 显示0~99

void Timer0Intial(void);//定时器0初始化

void EXT0_Intial(void);//外部中断0初始化

void EXT1_Intial(void);//外部中断1初始化

uint8_t count=0,TimeCount=0;//定时器基准计数变量

uint8_t Mode =2,ModeCount=0;//初始化为模式2左右循环

uint8_t PausePlay=1,PausePlayCount=0;//初始为播放模式

uint8_t Period=0;//计数周期

uint8_t BeerOpenFlag = 1;

uint8_t duanma[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//显示0-9

uint8_t LedData[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//LED查表数据

void main(void)//主函数

{

    beer=0;//关闭蜂鸣器

       EXT0_Intial();//外部中断0初始化

       EXT1_Intial();//外部中断1初始化

       Timer0Intial();//定时器0初始化    

       while(1)

       {

         display(Period);//显示循环的周期

      if(Rest==0)

      {

        delay(2);

        if(Rest==0)

         {

           while(!Rest);

           Mode =2;

           TimeCount=0;

           Period=0;

           P1 = 0xff;

         }

      }

       }

}

void delay(uint16_t DelayTime)//简单的延时函数

{

 uint8_t i=0;

 while(DelayTime--)

 {

   for(i=0;i<250;i++);   

 }

}

void display(uint8_t dis_data)//2位数码管显示函数

{

   P0 = duanma[dis_data/10];

       wei2=1;//显示十位的数据

       wei1=0;

       delay(1);

       P0 = duanma[dis_data%10];

       wei2=0;//显示个位

       wei1=1;

       delay(1);

}

void Timer0Intial(void)//定时器0初始化

{

       TMOD=0x01;

       TH0=(65536-50000)/256;

       TL0=(65536-50000)%256;

       ET0=1;

       EA=1;

       TR0=1;

}

void EXT0_Intial(void)//外部中断0初始化

{

       IT0=1;//下降沿触发

       EX0=1;//外部中断允许位

    PX0 = 1;//外部中断0为高优先级

    PX1 = 1;//外部中断1为高优先级

    PT0 = 0;//定时器0为低优先级

}

void EXT1_Intial(void)//外部中断1初始化 模式选择

{

       IT1=1;//下降沿触发

       EX1=1;//外部中断允许位

}

void Timer0() interrupt 1//定时器0中断服务程序 50ms

{

  TH0=(65536-50000)/256;

  TL0=(65536-50000)%256;

  count++;

  if(count>20)//LED 扫描的速度 500ms

  {

    count = 0;

    if(PausePlay ==1)//只有在播放模式才工作

      {

        TimeCount ++; //200ms 定时基准

        //Period++;

      }

    if(Period>99)   //当周期大于99时清零

     {

       Period = 0;

     } 

   if(TimeCount ==1)//第一个LED亮

      {

        if(BeerOpenFlag)

         BeerOn;     //打开蜂鸣器     

      }

    if(TimeCount == 2)//第二个200ms时 关闭蜂鸣器

      BeerOff;

    if(TimeCount < 9)

     {

       P1=LedData[TimeCount-1];

     }

    else

     {

       if(Mode==1) //模式一单方向循环

        {

          P1=LedData[TimeCount-9];//赋LED数据

          if(TimeCount ==9)//第一个LED亮

            { 

               if(BeerOpenFlag)

                 BeerOn;           

            }

          if(TimeCount == 10)

             BeerOff;

        }

       if(Mode==2)  //模式二 双向循环

        {

          P1=LedData[15-TimeCount];//赋LED控制数据    

        }

       if(Mode == 1)//模式1周期为16

        {

         if(TimeCount > 15) //当定时器基准计数到16时清零计数

           TimeCount =0;

        }

       if(Mode == 2)//模式2周期为14

        {

          if(TimeCount > 13)

           TimeCount =0;

        }

     }  

  }

}

void EXT0()interrupt 0//外部中断0中断服务程序 暂停播放控制

{

  PausePlayCount++;

  if(PausePlayCount==1)//第一次按键

    {

      PausePlay = 0;//Pause

      BeerOff;

    }

  if(PausePlayCount > 1)//第二次按键

   {

      PausePlay = 1;//Play

      PausePlayCount =0;

   }

}

void EXT1()interrupt 2//外部中断1中断服务程序

  ModeCount++;

  if(ModeCount==1)  //第一次按键 模式一

    {

      Mode = 1;

      TimeCount = Period % 8;//模式切换Led同时也切换

      if(TimeCount == 1)//模式切换时不让蜂鸣器误判     

        BeerOpenFlag = 0;    

      else

        BeerOpenFlag = 1;

    }      

  if(ModeCount > 1) //第二次按键 模式二

    {

      Mode = 2;     

      ModeCount = 0;//清零按键计数

      TimeCount = Period % 14;//模式切换Led同时也切换

     if(TimeCount == 1)//模式切换时不让蜂鸣器误判     

        BeerOpenFlag = 0;    

      else

        BeerOpenFlag = 1;  

    }

 

}

8.2 提高项目的代码

#include<reg52.h>

#define uint8_t unsigned char

#define uint16_t unsigned int

sbit beer = P2^5;

void UART_Intial(void);//串口初始化

void UART_Send_char(uint8_t SendData);//串口发送字节函数

void UART_Send_string(uint8_t *StringData);//串口发送字符串函数

uint8_t LedData[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//LED查表数据

uint8_t rbuff[10],rcount=0,receive_ok=0;

void main(void)//主函数

{  

    P1=0xff;

    beer =0;

    UART_Intial();

    UART_Send_string("****MCU and PC Connect Ok****");      

       while(1)

       {    

      if(receive_ok==1)

       {    

               if(rbuff[rcount-3]=='w')

                {

                  P1 = LedData[0];////点亮第一个led

               UART_Send_string("  Command_wok  ");//返回上位机com1 ok

                  rcount =0;

                  receive_ok=0;

                }

                if((rbuff[rcount-4]=='w')&&(rbuff[rcount-3]=='c'))

                 {

                  P1 = LedData[1];//点亮第二个led

                  UART_Send_string("  Command_wcok  ");////返回上位机com2 ok

                  rcount =0;

                  receive_ok=0;

                 } 

                if((rbuff[rcount-5]=='w')&&(rbuff[rcount-4]=='c')&&(rbuff[rcount-3]=='y'))

                 {

                  P1 = LedData[2];//点亮第三个led

                  UART_Send_string("  Command_wcyok  ");//返回上位机com3 ok

                  rcount =0;

                  receive_ok=0;

                 }       

             rcount =0;

                receive_ok=0;

       }   

       }

}

void UART_Intial(void)//串口初始化

{

       TMOD=0x20;//定时器0为方式2自动重装

    TH1=0xfd;//前提晶振是11.0592mhz

       TL1=0xfd;

       EA=1;

       ES=1;//串口中断允许位

       TR1=1;

    REN=1;//串口接受端

    SM0=0;//串口通信方式为8位异步通信

    SM1=1;

}

void UART_Send_char(uint8_t SendData)//串口发送字节函数

{

   SBUF = SendData;

   while(!TI);

   TI = 0;

}

void UART_Send_string(uint8_t *StringData)//串口发送字符串函数

{

   while(*StringData)

   {

     UART_Send_char(*StringData);

     StringData++;

   }

}

void UART()interrupt 4//串口接收中断函数

{

 // ES = 0;

  if(RI)

   {

     rbuff[rcount++]=SBUF;//存储上位机发送的数据

     RI = 0;//清中断标志位  

   }

  if((rbuff[rcount-1]=='k')&&(rbuff[rcount-2]=='o'))//判断帧尾是不是ok

   {                                                                    

         receive_ok=1;//接受完成

   }

if(rcount>5)

{

  rcount =0;

  receive_ok=0;

}

//  ES = 1;

}

9 心得体会

通过两周的单片机的生产实习,从单片机最小系统的焊接,到数码管、跑马灯、蜂鸣器电路的焊接,最后到编写程序、下载、调试。程序的编写相对来说是最难的,因为所有的模块要同时工作,最后我们选择了用定时器提供时间片段的编程思想进行编写程序,逐个模块的调试,最后实现了老师要求的功能。提高项目我们选择与上位机的串口通信,硬件电路我们需要另外焊接,老师要求上位机发给下位机的指令是不定长度的,这样的编程难度加大了很多,我才采用的通信协议是数据位+帧尾的模式,通过我们不懈的尝试最后实现了要求,另外我们还编写了我们自己使用的上位机调试上位机。这两周的学习我们学会了Altium Designer软件画原理图和PCB,学会了单片机的编程,以及VB上位机的编写。我相信这些实训将是我们走上工作岗位前的很好的历练,我们会再接再厉,进一步学习相关的专业知识。

10 参考文献

[1] 张美金,刘卉,谢国民.80C51单片机微机原理.辽宁人民出版社,2008:79~196.

[2] 谭浩强.C程序设计(第四版).清华大学出版社,2010:130~270

[3] 刘炳文.Visual Basic程序设计教程(第四版).清华大学出版社,2009:81~189

[4] 童诗白,华成英.模拟电子技术基础(第四版).高等教育出版社,2011:28~110

[5] 阎石.数字电子技术基础(第五版).高等教育出版社,2011:1~50

相关推荐