proteus仿真stc15

您所在的位置:网站首页 pvc芯片卡制作流程视频讲解 proteus仿真stc15

proteus仿真stc15

#proteus仿真stc15| 来源: 网络整理| 查看: 265

转载自: https://blog.csdn.net/weixin_44578655/article/details/105646300

文章目录 简要2020.4.20:今日测试: IO口模式配置 、LCD12864 、硬件PWM 2020.5.16今日测试:定时器1T/12T模式 2020.5.20今日测试:串口收发数据 2020.5.21今日测试:矩阵键盘 2020.5.26今日测试:SPI驱动74HC595 2020.6.3今日测试:ADC

简要

proteus在8.9版本正式支持stc单片机,虽然只有一个型号(stc15w4k32s4),不过这是stc家功能很齐全的一款的单片机。 最近刚好开单片机课程使用的就是这款,因为疫情上网课没有实物,就用proteus做了一块仿真开发板。 仿真开发板的原型是stc家的一款试验箱: 在这里插入图片描述

仿真开发板全貌: 在这里插入图片描述 开发板链接: 链接:https://pan.baidu.com/s/1xeccrGQLA_kM-TxT5n8-fg 提取码:vwip

之所以选这款,是因为stc-isp有它的全部例程,开发板和例程都白嫖,还要啥自行车,当然仿真会有部分BUG,实物才是正道,例程我随缘测试吧,测试效果会后续更新,有想帮忙一起弄的小伙伴欢迎转载。 例程: 在这里插入图片描述

2020.4.20: 今日测试: IO口模式配置 、LCD12864 、硬件PWM

问题:

IO口模式无法配置,各IO口不管如何配置,都是准双向IO口模式,网上资料较少,没找到解释。 因为无法将IO口配置为高阻态,所以ADC无法测试。 后来发现例程对于ADC的初始化中,并没有将IO口配置为高阻态,后文我又重新测试了一下ADC。

proteus自带的库中,没有淘宝常见的那种带中文字库的LCD12864,在网上翻到有大佬做了一个: http://www.51hei.com/bbs/dpj-94761-1.html 折腾了一下午,能显示了,但这个12864有BUG,只能显示汉字,不支持ASCII码,而且显示屏左上角的定位孔必须与原理图原点的位置重合,才能显示正常,若不对齐,效果如下: 在这里插入图片描述 对齐以后效果如下(屏幕左侧的几串数字估计也是BUG): 在这里插入图片描述 硬件PWM正常,效果如下: 在这里插入图片描述

2020.5.16 今日测试:定时器1T/12T模式

有同学反应proteus仿真STC15时,时钟不正确。 今天测试了一下,时钟是准确的。 之前还担心,stc15的定时器工作在1T模式下和12T模式下,proteus能否仿真出真实的效果。今天测试了一下,12T模式下仿真的确比1T模式下仿真慢12倍。

先设为12T模式: 在这里插入图片描述

在12T模式下,程序运行至12s时,引脚输出发生跳变,小灯亮起: 在这里插入图片描述 配置为1T模式,程序仅改这一处: 在这里插入图片描述

程序运行至1s,引脚跳变,小灯亮起,比12T模式下快12倍 在这里插入图片描述

proteus仿真时运行比较慢,左下角的计时才是程序真实的运行时间。

2020.5.20 今日测试:串口收发数据

proteus中提供了一个虚拟串口终端,类似串口助手可以收发数据。 在这里插入图片描述 51单片机的串口收发有两种方式:中断方式和查询方式。 在仿真中串口发送使用查询方式和中断方式都可以,数据正常。 串口接收时,仅能使用中断方式,查询方式无法正常收到数据,测试时发现RI始终没被置一。

串口相关代码:

void UART_Init(void) { ACC = P_SW1; ACC &= ~(S1_S0 | S1_S1); //S1_S0=0 S1_S1=0 P_SW1 = ACC; //(P3.0/RxD, P3.1/TxD) SCON = 0x50; //8位可变波特率 AUXR = 0x40; //定时器1为1T模式 TMOD = 0x00; //定时器1为模式0(16位自动重载) TL1 = (65536 - (FOSC/4/BAUD)); //设置波特率重装值 TH1 = (65536 - (FOSC/4/BAUD))>>8; TR1 = 1; //定时器1开始启动 ES = 1; //使能串口中断 EA = 1; } void Uart() interrupt 4 using 1 { if (RI) { RI = 0; // rx_temp = SBUF; } if (TI) { TI = 0; // busy = 0; // } } void SendData(unsigned char dat) { while (busy); // ACC = dat; // busy = 1; SBUF = ACC; // } 2020.5.21 今日测试:矩阵键盘

开发板原来使用的是P0口接矩阵键盘,但在proteus中的STC15的P0口有严重的BUG,详见这篇帖子: https://blog.csdn.net/weixin_44578655/article/details/106245015 我把P0换成了P6,并且将限流、上拉电阻全部去掉了,总算能凑合用了。 在这里插入图片描述 我没使用stc-isp里的矩阵键盘例程(没看太懂),自己按习惯写了一个:

//矩阵键盘扫描函数 //有按键按下时返回字符:'0'~'F',无按键按下时返回0 uchar IO_KeyScan(void) { uchar X_temp = 0,Y_temp = 0; uchar Key_res = 0; static Key_down = 0; P6 = 0XFF; //未知BUG,必须加这句,否则下次读到的数据是错的 P6 = 0XF0; //高4位置1,低4位置0,此时有按键按下时,高四位的某一位会被拉低,由此定位按下的按键在第几行 X_temp = P6 ^ 0XF0; if(X_temp ) //如果检测到某行有按键按下(有按键按下时,高四位会有一位被拉低) { if(Key_down == 0) //等待按键松开,防止重入 { switch(X_temp) { case 0x80: P6 = 0XFF; //未知BUG,必须加这句,否则下次读到的数据是错的 P6 = 0X0F; //低4位置1 Y_temp = P6 ^ 0X0F; switch(Y_temp) { case 0x08: Key_res = 'F'; break; case 0x04: Key_res = 'E'; break; case 0x02: Key_res = 'D'; break; case 0x01: Key_res = 'C'; break; default: break; } break; case 0x40: P6 = 0XFF; P6 = 0X0F; Y_temp = P6 ^ 0X0F; switch(Y_temp) { case 0x08: Key_res = 'B'; break; case 0x04: Key_res = 'A'; break; case 0x02: Key_res = '9'; break; case 0x01: Key_res = '8'; break; default: break; } break; case 0x20: P6 = 0XFF; P6 = 0X0F; Y_temp = P6 ^ 0X0F; switch(Y_temp) { case 0x08: Key_res = '7'; break; case 0x04: Key_res = '6'; break; case 0x02: Key_res = '5'; break; case 0x01: Key_res = '4'; break; default: break; } break; case 0x10: P6 = 0XFF; P6 = 0X0F; Y_temp = P6 ^ 0X0F; switch(Y_temp) { case 0x08: Key_res = '3'; break; case 0x04: Key_res = '2'; break; case 0x02: Key_res = '1'; break; case 0x01: Key_res = '0'; break; default: break; } break; default: break; } } } else Key_down = 0; //按键被松开 if(Key_res) Key_down = 1; //标志按键被按下,防止重入 return Key_res; }

测试结果: 依次按下16个按键,串口输出的数据’0’~‘F’ 在这里插入图片描述

2020.5.26 今日测试:SPI驱动74HC595

74HC595是一颗串行输入并行输出的IC,通常用来驱动数码管、led点阵等,可以节省很多IO口. 74HC595的时序跟SPI很像,所以可以用硬件SPI驱动74HC595 。 在开发板上,74HC595用来驱动数码管,连接的就是SPI1的引脚。

跟串口类似,SPI发送数据同样有两种方式:查询方式和中断方式,这两种方式在仿真中均正常。

由于spi1的引脚有好几组,开发板上使用的是P4.3、P4.0、P5.4这一组引脚,选择哪一组引脚需要通过程序配置。 stc-isp中与SPI相关的例程有好几个,它们配置SPI引脚的代码不一样(不知道为什么),主要有两种: 第一种:配置AUXR1 在这里插入图片描述 第二种:配置ACC和PSW 在这里插入图片描述 在仿真中,第一种配置spi无效,第二种配置spi正常。

下面是查询方式和中断方式SPI发送数据的相关代码:

查询方式SPI初始化代码:

void spi_init() //spi初始化 { /****官方例程中出现的,去掉这一段后spi失效***/ ACC = P_SW1; //切换到第三组SPI ACC &= ~(SPI_S0 | SPI_S1); //SPI_S0=0 SPI_S1=1 ACC |= SPI_S1; //(P5.4/SS_3, P4.0/MOSI_3, P4.1/MISO_3, P4.3/SCLK_3) P_SW1 = ACC; SPSTAT = SPIF | WCOL; //清除SPI状态 /********/ SPCTL=(SSIG /****官方例程中出现的,去掉这一段后spi失效***/ ACC = P_SW1; //切换到第三组SPI ACC &= ~(SPI_S0 | SPI_S1); //SPI_S0=0 SPI_S1=1 ACC |= SPI_S1; //(P5.4/SS_3, P4.0/MOSI_3, P4.1/MISO_3, P4.3/SCLK_3) P_SW1 = ACC; SPSTAT = SPIF | WCOL; //清除SPI状态 /********/ SPCTL=(SSIG SPSTAT = SPIF | WCOL; //清除SPI状态位 g_fSpiBusy = FALSE; }

数码管扫描函数:

//数码管扫描 void seg7scan(unsigned char index1,unsigned char index2) { SPI_SendByte(~T_COM[index1]); //发送位选 SPI_SendByte(t_display[index2]);//发送段选 HC595_RCLK=1; //将P5.4置1,更新数据 HC595_RCLK=0; //将P5.4置0 } //消隐 void seg_clear(void) { SPI_SendByte(0x00); //位选清零 SPI_SendByte(0x00); //段选清零 HC595_RCLK=1; //将P5.4置1,更新数据 HC595_RCLK=0; //将P5.4置0 }

main函数的大循环:

while(1) { for(i=0;i P1M0 = 1; //将P1口配置为高阻态 P1M1 = 1; P1 = 0Xff; P1ASF = 0xff; //设置P1口为AD口 ADC_RES = 0; //清除结果寄存器 ADC_CONTR = ADC_POWER | ADC_SPEEDLL; Delay(2); //ADC上电并延时 } /*---------------------------- 读取ADC结果 参数:ch,通道0~7 ----------------------------*/ BYTE GetADCResult(BYTE ch) { ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START; _nop_(); //等待4个NOP _nop_(); _nop_(); _nop_(); while (!(ADC_CONTR & ADC_FLAG));//等待ADC转换完成 ADC_CONTR &= ~ADC_FLAG; //Close ADC return ADC_RES; //返回ADC结果 }

输出结果时,又发现一点问题,原来是打算把ADC的结果(8位)使用sprintf格式化输出为字符,但这种方式打印出的数据完全错误…

/***下面这样使用sprintf出问题,未知bug***/ sprintf(tx_temp,"ch%d:%x\r\n",ch,GetADCResult(ch)); SendString(tx_temp); //串口发送字符串 /******/

现象: 在这里插入图片描述 只能直接发送16进制数:

/***只发送1字节16进制数,数据正常***/ SendData(GetADCResult(ch)); /******/

注意在串口终端窗口处右键勾选Hex Display Mode



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3