找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3240|回复: 2
打印 上一主题 下一主题
收起左侧

一种简易单片机计数器程序Proteus仿真 带详细注释

[复制链接]
跳转到指定楼层
楼主
计数器仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)


单片机源程序如下:
  1. #include <reg52.h>                        // 包含头文件
  2. #include <intrins.h>

  3. #define uchar unsigned char                // 以后unsigned char就可以用uchar代替
  4. #define uint  unsigned int                // 以后unsigned int 就可以用uint 代替

  5. sfr ISP_DATA  = 0xe2;                        // 数据寄存器
  6. sfr ISP_ADDRH = 0xe3;                        // 地址寄存器高八位
  7. sfr ISP_ADDRL = 0xe4;                        // 地址寄存器低八位
  8. sfr ISP_CMD   = 0xe5;                        // 命令寄存器
  9. sfr ISP_TRIG  = 0xe6;                        // 命令触发寄存器
  10. sfr ISP_CONTR = 0xe7;                        // 命令寄存器

  11. sbit w1      = P2^4;                         // 数码管第1位的控制引脚
  12. sbit w2      = P2^5;                        // 数码管第2位的控制引脚
  13. sbit w3      = P2^6;                        // 数码管第3位的控制引脚
  14. sbit w4      = P2^7;                        // 数码管第4位的控制引脚
  15. sbit Red     = P1^0;                        // 红外模块
  16. sbit Led     = P1^1;                        // LED灯
  17. sbit Buzzer  = P2^3;                        // 蜂鸣器引脚
  18. sbit KeySet  = P3^2;                        // 设置按键
  19. sbit KeyDown = P3^3;                        // 减按键
  20. sbit KeyUp   = P3^4;                        // 加按键


  21. /*   数码管的显示值:  0    1    2    3    4    5     6   7    8    9    -       */
  22. uchar code Array1[]={ 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x00 };

  23. uchar Buff[4];                                        // 显示缓冲区
  24. uchar ShowID=1;                                        // 当前显示的是哪一个数码管

  25. int gAlarm;                                                        // 报警值
  26. int gCount=0;                                                // 计数值


  27. /*********************************************************/
  28. // 单片机内部EEPROM不使能
  29. /*********************************************************/
  30. void ISP_Disable()
  31. {
  32.         ISP_CONTR = 0;
  33.         ISP_ADDRH = 0;
  34.         ISP_ADDRL = 0;
  35. }


  36. /*********************************************************/
  37. // 从单片机内部EEPROM读一个字节,从0x2000地址开始
  38. /*********************************************************/
  39. unsigned char EEPROM_Read(unsigned int add)
  40. {
  41.         ISP_DATA  = 0x00;
  42.         ISP_CONTR = 0x83;
  43.         ISP_CMD   = 0x01;
  44.         ISP_ADDRH = (unsigned char)(add>>8);
  45.         ISP_ADDRL = (unsigned char)(add&0xff);
  46.         // 对STC89C51系列来说,每次要写入0x46,再写入0xB9,ISP/IAP才会生效
  47.         ISP_TRIG  = 0x46;           
  48.         ISP_TRIG  = 0xB9;
  49.         _nop_();
  50.         ISP_Disable();
  51.         return (ISP_DATA);
  52. }


  53. /*********************************************************/
  54. // 往单片机内部EEPROM写一个字节,从0x2000地址开始
  55. /*********************************************************/
  56. void EEPROM_Write(unsigned int add,unsigned char ch)
  57. {
  58.         ISP_CONTR = 0x83;
  59.         ISP_CMD   = 0x02;
  60.         ISP_ADDRH = (unsigned char)(add>>8);
  61.         ISP_ADDRL = (unsigned char)(add&0xff);
  62.         ISP_DATA  = ch;
  63.         ISP_TRIG  = 0x46;
  64.         ISP_TRIG  = 0xB9;
  65.         _nop_();
  66.         ISP_Disable();
  67. }


  68. /*********************************************************/
  69. // 擦除单片机内部EEPROM的一个扇区
  70. // 写8个扇区中随便一个的地址,便擦除该扇区,写入前要先擦除
  71. /*********************************************************/
  72. void Sector_Erase(unsigned int add)         
  73. {
  74.         ISP_CONTR = 0x83;
  75.         ISP_CMD   = 0x03;
  76.         ISP_ADDRH = (unsigned char)(add>>8);
  77.         ISP_ADDRL = (unsigned char)(add&0xff);
  78.         ISP_TRIG  = 0x46;
  79.         ISP_TRIG  = 0xB9;
  80.         _nop_();
  81.         ISP_Disable();
  82. }


  83. /*********************************************************/
  84. // 毫秒级的延时函数,time是要延时的毫秒数
  85. /*********************************************************/
  86. void DelayMs(uint time)
  87. {
  88.         uint i,j;
  89.         for(i=0;i<time;i++)
  90.                 for(j=0;j<112;j++);
  91. }


  92. /*********************************************************/
  93. // 定时器初始化
  94. /*********************************************************/
  95. void TimerInit()
  96. {
  97.         TMOD = 0x01;                                        // 使用定时器0,工作方式1         
  98.         TH0  = 248;                                                // 给定时器0的TH0装初值
  99.         TL0  = 48;                                                // 给定时器0的TL0装初值
  100.         ET0  = 1;                                                        // 定时器0中断使能
  101.         EA   = 1;                                                        // 打开总中断
  102.         TR0         = 1;                                                        // 启动定时器0
  103. }


  104. /*********************************************************/
  105. // 显示数字
  106. /*********************************************************/
  107. void ShowNum(int dat)
  108. {
  109.         Buff[1]=Array1[dat/100];                        // 显示百位
  110.         Buff[2]=Array1[dat%100/10];                // 显示十位
  111.         Buff[3]=Array1[dat%10];                                // 显示个位
  112. }


  113. /*********************************************************/
  114. // 报警判断
  115. /*********************************************************/
  116. void AlarmJudge()
  117. {
  118.         if(gCount>gAlarm)                        // 计数值大于报警值
  119.         {
  120.                 Led=0;                                                        // 点亮LED
  121.                 Buzzer=0;                                                // 启动蜂鸣器
  122.         }
  123.         else                                                        
  124.         {
  125.                 Led=1;                                                        // 关闭LED
  126.                 Buzzer=1;                                                // 关闭蜂鸣器
  127.         }
  128. }


  129. /*********************************************************/
  130. // 按键扫描
  131. /*********************************************************/
  132. void KeyScanf()
  133. {
  134.         if(KeySet==0)                                                                // 如果设置按键被按下
  135.         {
  136.                 Buff[0]=Array1[10];                                // 数码管第一位显示“-”,表示当前显示的是报警值
  137.                 ShowNum(gAlarm);                                        // 显示报警值
  138.                 DelayMs(10);                                                        // 延时去抖
  139.                 while(!KeySet);                                                // 等待按键释放
  140.                 DelayMs(10);                                                        // 延时去抖
  141.                
  142.                 while(1)
  143.                 {
  144.                         if(KeyDown==0)                                        // 如果“减”按键被按下
  145.                         {
  146.                                 if(gAlarm>1)                                        // 判断当前报警值是否大于1
  147.                                 {
  148.                                         gAlarm--;                                                // 报警值减1
  149.                                         ShowNum(gAlarm);                // 刷新显示改变后的报警值
  150.                                         DelayMs(200);                                // 延时
  151.                                 }
  152.                         }
  153.                         
  154.                         if(KeyUp==0)                                                // 如果“加”按键被按下                                       
  155.                         {
  156.                                 if(gAlarm<999)                                // 判断当前报警值是否小于999
  157.                                 {
  158.                                         gAlarm++;                                                // 报警值减1
  159.                                         ShowNum(gAlarm);                // 刷新显示改变后的报警值
  160.                                         DelayMs(200);                                // 延时
  161.                                 }
  162.                         }
  163.                         
  164.                         if(KeySet==0)                                                // 如果“设置”按键被按下
  165.                         {
  166.                                 break;                                                                // 退出报警值设置,回到测量界面
  167.                         }
  168.                 }
  169.                
  170.                 /* 退出设置模式 */
  171.                 Buff[0]=Array1[11];                                // 数码管第一位显示“ ”,表示当前显示的是测量值
  172.                 ShowNum(gCount);                                        // 显示报警值
  173.                 DelayMs(10);                                                        // 延时去抖
  174.                 while(!KeySet);                                                // 等待按键释放
  175.                 DelayMs(10);                                                        // 延时去抖
  176.                
  177.                 Sector_Erase(0x2000);                                                        // 保存报警距离
  178.                 EEPROM_Write(0x2000,gAlarm/100);
  179.                 EEPROM_Write(0x2001,gAlarm%100);
  180.         }
  181. }


  182. /*********************************************************/
  183. // 报警值初始化
  184. /*********************************************************/
  185. void AlarmInit()
  186. {
  187.         gAlarm=EEPROM_Read(0x2000)*100+EEPROM_Read(0x2001);                // 从EEPROM读取报警值

  188.         if((gAlarm==0)||(gAlarm>999))                        // 如果读取到的报警值异常(等于0或大于999则认为异常)
  189.         {
  190.                 gAlarm=25;                                                                                        // 重新赋值报警值为25
  191.         }
  192. }


  193. /*********************************************************/
  194. // 主函数
  195. /*********************************************************/
  196. void main()
  197. {
  198.         TimerInit();                                                        // 定时器0的初始化(数码管的动态扫描)
  199.         AlarmInit();                                                        // 报警值初始化
  200.         
  201.         Buff[0]=Array1[11];                                // 刚上电显示" 000"
  202.         Buff[1]=Array1[0];
  203.         Buff[2]=Array1[0];
  204.         Buff[3]=Array1[0];
  205.         
  206.         while(1)
  207.         {
  208.                 if(Red==0)                                                        // 如果红外模块检测到有障碍物
  209.                 {
  210.                         if(gCount<999)                                // 判断当前计数是否小于999
  211.                         {
  212.                                 gCount++;                                                // 计数加1
  213.                                 ShowNum(gCount);                // 刷新显示
  214.                         }
  215.                         Buzzer=0;                                                        // 蜂鸣器嘀一声
  216.                         DelayMs(50);
  217.                         Buzzer=1;
  218.                         while(!Red);                                        // 等待障碍物离开传感器检测范围
  219.                         DelayMs(100);
  220.                 }

  221.                 AlarmJudge();                                                // 判断是否需要报警
  222.                
  223.                 KeyScanf();                                                        // 按键扫描                                                        
  224.         }
  225. }


  226. /*********************************************************/
  227. // 定时器0服务程序
  228. /*********************************************************/
  229. void Timer0(void) interrupt 1
  230. {
  231.         TH0  = 248;                                // 给定时器0的TH0装初值
  232.         TL0  = 48;                                // 给定时器0的TL0装初值

  233.         P0=0x00;                                        // 先关闭所有显示
  234.         w1=1;
  235.         w2=1;
  236.         w3=1;
  237.         w4=1;

  238.         if(ShowID==1)                          // 判断是否显示第1位数码管
  239.         {
  240.                 w1=0;                                                   // 打开第1位数码管的控制开关
  241.                 P0=Buff[0];                           // 第1位数码管显示内容        
  242.         }
  243.         
  244.         if(ShowID==2)                          // 判断是否显示第2位数码管
  245.         {
  246.                 w2=0;                                                   // 打开第2位数码管的控制开关
  247.                 P0=Buff[1];                           // 第2位数码管显示内容        
  248.         }
  249.         
  250.         if(ShowID==3)                          // 判断是否显示第3位数码管
  251.         {
  252.                 w3=0;                                                   // 打开第3位数码管的控制开关
  253.                 P0=Buff[2];                           // 第3位数码管显示内容        
  254.         }
  255.         
  256.         if(ShowID==4)                          // 判断是否显示第4位数码管
  257.         {
  258.                 w4=0;                                                   // 打开第4位数码管的控制开关
  259.                 P0=Buff[3];                           // 第4位数码管显示内容        
  260.         }        
  261.         
  262.         ShowID++;                                          // 切换到下一个数码管的显示
  263.         if(ShowID==5)
  264.                 ShowID=1;
  265. }
复制代码

所有资料51hei提供下载:
计数器.zip (142.71 KB, 下载次数: 45)


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏3 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:197229 发表于 2021-3-31 05:29 | 只看该作者
谢谢楼主,下载了仿真例程和程序,正常运行我是做了一点儿小小的改动,在输出输入处,算是狗尾续貂了,觉得很有用。

调整大小 jsq.jpg (138.61 KB, 下载次数: 106)

调整大小 jsq.jpg
回复

使用道具 举报

板凳
ID:820198 发表于 2021-3-31 09:22 | 只看该作者
不错啊,很清晰的程序
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表