peoteus仿真单片机模拟仿真软件与单片机模拟仿真软件通信需要虚拟串口吗?

实验目的利用PROTUES仿真软件、串口调试助手、虚拟串口,搭建单片机与PC通信仿真平台,熟悉单片机串口的配置及与PC机的通信方法;尝试制定通信协议,单片机根据通信协议解析接收到的内容,并根据接收的指令执行相应的操作。实验内容1、搭建实验电路,利用proteus仿真2、实现以下效果**效果1:**利用定时器的定时功能,用6位数码管实现时、分、秒的显示及更新;**效果2:**制定通信协议,PC机发送数据给单片机,根据发送的指令控制数码管显示时间值的“暂停”及“重启”代码#include<reg52.h>
#define u8 unsigned char
#define u16 unsigned int
sbit SW1=P0^0;
sbit SW2=P1^1;
sbit SW3=P2^2;
sbit LED=P3^7;
bit Flag=0;
u8 Data[]={ 0x3f
, 0x06 , 0x5b , 0x4f , 0x66 , 0x6d,
0x7d , 0x07 , 0x7f
, 0x6f , 0x77 , 0x7c ,
0x39 , 0x5e , 0x79 , 0x71 , 0x00 } ;
u8 Wei[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf};
u8 Hour,Min,Sec;
u8 A;
u8 SetTime;
#define Confirm
0
#define Set_sec
1
#define Set_min
2
#define Set_hour 3
void Delay( u16 z );
void Display(u8 Hour,u8 Min,u8 Sec);
void Key();
void Init();
void Putchar(u8 a);
void Putstr(u8 *s);
void Uartinit();
main()
{
u8 i;
Uartinit();
Putstr("Program start");
P2=0;
Init();
while(1)
{
Key();
Display( Hour, Min, Sec);
}
}
void Init()
{
//************初始化定时器**********
TMOD
=0X01; //定时器工作方式1
TH0=0X3C;
//定时器初始值
TL0=0XAF;
ET0=1;
//中断允许
EA=1;
TR0=1;
//启动定时器0
//************串口**********
}
void Timer0 () interrupt 1 //时间函数
{
static u8 count=0;
count++;
if(count==2)
{
count=0;
Sec++;
if(Sec>59)
{
Sec=0;
Min++;
if(Min>59)
{
Min=0;
Hour++;
if(Hour>23)
{
Hour=0;
}
}
}
}
TH0=0X3C;
//定时器初始值
TL0=0XAF;
}
void Delay( u16 z ) //延时函数
{
u16 x,y;
for(x=0;x<z;x++)
for(y=0;y<110;y++)
{
;
}
}
void Display(u8 Hour,u8 Min,u8 Sec)
//显示函数
{
u8
Hour_shi,Hour_ge,Min_shi,Min_ge,Sec_shi,Sec_ge;
Hour_shi=Hour/10;
Hour_ge=Hour%10;
Min_shi=Min/10;
Min_ge=Min%10;
Sec_shi=Sec/10;
Sec_ge=Sec%10;
//**********时************
P2=0xff;
P1=Data[Hour_shi];
P2=0xfe;
if(SetTime==Set_hour)
{
Delay( 1 );
}
else
{
Delay( 10 );
}
P2=0xff;
P1=Data[Hour_ge];
P2=0xfd;
if(SetTime==Set_hour)
{
Delay( 1 );
}
else
{
Delay( 10 );
}
//**********分************
P2=0xff;
P1=Data[Min_shi];
P2=0xfb;
if(SetTime==Set_min)
{
Delay( 1 );
}
else
{
Delay( 10 );
}
P2=0xff;
P1=Data[Min_ge];
P2=0xf7;
if(SetTime==Set_min)
{
Delay( 1 );
}
else
{
Delay( 10 );
}
//**********秒************
P2=0xff;
P1=Data[Sec_shi];
P2=0xef;
if(SetTime==Set_sec)
{
Delay( 1 );
}
else
{
Delay( 10 );
}
P2=0xff;
P1=Data[Sec_ge];
P2=0xdf;
if(SetTime==Set_sec)
{
Delay( 1 );
}
else
{
Delay( 10 );
}
}
void Key()
//按键函数
{
if(SW1==0)
{
Delay(10);
if(SW1==0) //消除抖动
{
LED=~LED;
SetTime++;
if(SetTime>Set_hour)
{
SetTime=Confirm; //0
}
}
while(SW1==0) //松手检测
{
Display( Hour, Min, Sec);
}
}
//Confirm Set_hour
Set_sec Set_min
if(SW2==0)
//加1
{
Delay(10);
if(SW2==0)
{
switch(SetTime)
{
case Set_hour:
//3
if(Hour>=23)
{
Hour=0;
}
else
{
Hour++;
}
break;
case Set_min:
//2
if(Min>=59)
{
Min=0;
}
else
{
Min++;
}
break;
case Set_sec:
if(Sec>=59)
{
Sec=0;
}
else
{
Sec++;
}
break;
case Confirm: break;
default: break;
}
}
}
while(SW2==0) //松手检测
{
Display( Hour, Min, Sec);
}
if(SW3==0)
//减1
{
Delay(10);
if(SW3==0)
{
switch(SetTime)
{
case Set_hour:
if(Hour<=0)
{
Hour=0;
}
else
{
Hour--;
}
break;
case Set_min:
if(Min<=0)
{
Min=0;
}
else
{
Min--;
}
break;
case Set_sec:
if(Sec<=0)
{
Sec=0;
}
else
{
Sec--;
}
break;
case Confirm: break;
default: break;
}
}
}
while(SW3==0) //松手检测
{
Display( Hour, Min, Sec);
}
}
void Uartinit()
//初始化串口
{
TMOD
=0X20; //T1 工作方式2,自动重装载 TMOD&0X0F|0X20;
TH1=0XFD;
TL1=0XFD; //初始值 波特率9600
TR1=1;
//启动定时器
SCON=0X50;
PCON&=0X7F;
EA=1;
ES=0;
}
void Putchar(u8 a)
//接收数据
{
ES=0;
SBUF=a;// 'A' " dsfsdfsd"
A
while(TI==0);
TI=0;
ES=1;
}
void Putstr(u8 *s)
//Putstr("Program start");
{
while(*s!='\0')
{
Putchar(*s);
s++;
}
}
void Uart() interrupt 4
//串口中断
{
if(RI==1)
{
RI=0;
A=SBUF;
if(A=='p')
{
TR0=0;
}
if(A=='r')
{
TR0=1;
}
Putchar(A);
}
实验结果ps:关注并私信我免费发仿真图已经完整工程
--------元器件图标、名称分类目录---------- proteus元器件符号及名称
* ==1. 单片机最小系统元器件==
2. 单片机基础元器件(基本上每个电路图都会用到的)3. 单只数码管循环显示0~94. 8只数码管滚动显示单个数字5. 继电器控制照明设备6. INT0中断计数7. 8X8LED点阵显示数字8. 用定时器设计的门铃9. 串行数据转换未并行数据10. 甲机通过串口控制乙机LED11. LCD1602字符液晶滚动演示程序1. 单片机最小系统元器件上图是以89C51单片机的最小系统为例。晶振—CRYSTAL电容—02013A220JAT2A电解电容----CAP-ELEC电阻—res2. 单片机基础元器件(基本上每个电路图都会用到的)发光二极管—LED-BLUE,LED-YELLOW,LED-GREEN分别是蓝灯,黄灯,绿灯(随便选)按钮—BUTTON3. 单只数码管循环显示0~9数码管—7SEG-COM-CAT- ** ,(共阴极)共阳的话就是7SEG-COM-AN-**4. 8只数码管滚动显示单个数字7段8个数码管—7SEG-MPX6-CA-BLUE (共阳极)(另附:共阴极:7SEG-MPX6-CC-BLUE)电阻—RX8(另附:上拉电阻—RESPACK-7)三极管—NPN5. 继电器控制照明设备灯泡—LAMP继电器—RTE24005F二极管—DIODE三极管—NPN三极管—PNP6. INT0中断计数上拉电阻—RESPACK-77. 8X8LED点阵显示数字芯片—74LS245上拉电阻—RESPACK-88. 用定时器设计的门铃蜂鸣器—SOUNDER示波器—左侧菜单栏9. 串行数据转换未并行数据芯片—7416410. 甲机通过串口控制乙机LED甲机给乙机通信整体电路图串口模型器件—CONN-D9F串口通信芯片—MAX232极性电容—CAP-POL11. LCD1602字符液晶滚动演示程序滑动变阻器—POT-HG (左边两个上下的箭头可以调节电阻的大小哦)上拉电阻—RESPACK-8液晶LCD—下图来说明吧。 (注:其中Description列名了分辨率,16x2即为1602)
1.Keil5软件介绍keil是一款广泛用于嵌入式系统开发的软件工具。它支持多种常见的微型控制器架构和编程语言,并提供了丰富的调试辅助功能,可以帮助开发人员在嵌入式系统开发过程中提高效率,缩短开发周期,是嵌入式系统开发领域的重要工具之一。Keil软件的主要功能和作用1.提供集成化的开发环境2.支持多种芯片体系结构,例如ARM、8051、C251等3.提供强大的调试功能4.内置丰富的库函数和示例代码5.可以连线多种仿真器和调试器Keil软件的优点1.跨平台支持,可在Window、Linux等操作系统上运行2.易于使用3.支持多种编程语言,如C、C++、ASM等4.丰富的API和库函数5.高效的编译器6.强大的调试功能2.Protues软件介绍Proteus是英国著名的EDA工具(仿真软件),从原理图布图、代码调试到单片机与外围电路协同仿真,一键切换到PCB设计,真正实现了从概念到产品的完整设计。是世界上唯一将电路仿真软件、PCB设计软件和虚拟模型仿真软件三合一的设计平台,其处理器模型支持8051、HC11、PIC10/12/16/18/24/30/DSPIC33、AVR、ARM、8086和MSP430等,2010年又增加了Cortex和DSP系列处理器,并持续增加其他系列处理器模型。在编译方面,它也支持IAR、Keil和MATLAB等多种编译器。Protues软件功能1.原理布图2.PCB自动或人工布线3.SPICE电路仿真Protues软件特点1.互动的电路仿真用户甚至可以实时采用诸如RAM,ROM,键盘,马达,LED,LCD,AD/DA,部分SPI器件,部分IIC器件。2.仿真处理器及其外围电路可以仿真51系列、AVR、PIC、ARM、等常用主流单片机。还可以直接在基于原理图的虚拟原型上编程,再配合显示及输出,能看到运行后输入输出的效果。配合系统配置的虚拟逻辑分析仪、示波器等,Proteus建立了完备的电子设计开发环境。(一)利用Keil和protues完成51单片机的简单仿真(流水灯)1.在Keil软件中编写51程序打开Keil软件,选择创建新工程输入文件名在Atmel中找到AT89C51,然后确定新建一个文档然后把代码写进去,参考如下#include <reg51.h>
#include <intrins.h>
void delay(int a)
{
int i,j;
for(i=0;i<a;i++)
{
for(j=0;j<1000;j++) _nop_();
}
}
void main(void)
{
char st[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
int t=0;
while(1)
{
P0=st[t];
delay(50);
t++;
if(t==8){
t=0;
}
}
}
然后将文档进行保存,记得以.c为后缀命名然后双击Source Group 1找到刚刚创建的LED2.c加入进去打开Source Group 1可以看见LED2.c加进去了然后打开魔法棒选择Output,打开Creat HEX file最后进行编译,可以看见没有错误2.在protues中进行仿真打开protues,选择新建工程选择下一步选择原理图DAFAULT,然后下一步不用创建PCB布板设计,直接下一步也不用创建固件项目,直接下一步然后点完成进入原理图绘制界面,找到左上的P搜索AT89C51再搜索LED然后返回之前的界面,找到电源然后将上述找到的元件链接起来然后右键点击51单片机,选择编辑属性,点击文件夹,将刚刚生成的LED2.hex文件添加然后点完成。3.仿真上述步骤完成后,点击左下角的仿真查看仿真结果交通灯 - Proteus 8 Professional - 原理图绘制 2023-09-24 17-26-19(二)ARM开发,使用MDK编译简单STM32程序(LED灯闪烁)1.使用Keil编写程序创建工程部份和上述51单片机一致,在选择stm32型号时使用STM32F103R6按照下图选择序号代码如下(参考ARM开发:使用MDK编译stm32简单程序(闪烁LED))#define PERIPH_BASE
((unsigned int)0x40000000)//AHB
#define APB2PERIPH_BASE
(PERIPH_BASE + 0x10000)
#define GPIOA_BASE
(APB2PERIPH_BASE + 0x0800)
//GPIOA_BASE=0x40000000+0x10000+0x0800=0x40010800,该地址为GPIOA的基地址
#define GPIOB_BASE
(APB2PERIPH_BASE + 0x0C00)
//GPIOB_BASE=0x40000000+0x10000+0x0C00=0x40010C00,该地址为GPIOB的基地址
#define GPIOC_BASE
(APB2PERIPH_BASE + 0x1000)
//GPIOC_BASE=0x40000000+0x10000+0x1000=0x40011000,该地址为GPIOC的基地址
#define GPIOD_BASE
(APB2PERIPH_BASE + 0x1400)
//GPIOD_BASE=0x40000000+0x10000+0x1400=0x40011400,该地址为GPIOD的基地址
#define GPIOE_BASE
(APB2PERIPH_BASE + 0x1800)
//GPIOE_BASE=0x40000000+0x10000+0x0800=0x40011800,该地址为GPIOE的基地址
#define GPIOF_BASE
(APB2PERIPH_BASE + 0x1C00)
//GPIOF_BASE=0x40000000+0x10000+0x0800=0x40011C00,该地址为GPIOF的基地址
#define GPIOG_BASE
(APB2PERIPH_BASE + 0x2000)
//GPIOG_BASE=0x40000000+0x10000+0x0800=0x40012000,该地址为GPIOG的基地址
#define GPIOA_ODR_Addr
(GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr
(GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr
(GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr
(GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr
(GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr
(GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr
(GPIOG_BASE+12) //0x40011E0C
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr)
*((volatile unsigned long
*)(addr))
#define LED0
MEM_ADDR(BITBAND(GPIOA_ODR_Addr,8))
//#define LED0 *((volatile unsigned long *)(0x422101a0)) //PA8
//定义typedef类型别名
typedef
struct
{
volatile
unsigned
int
CR;
volatile
unsigned
int
CFGR;
volatile
unsigned
int
CIR;
volatile
unsigned
int
APB2RSTR;
volatile
unsigned
int
APB1RSTR;
volatile
unsigned
int
AHBENR;
volatile
unsigned
int
APB2ENR;
volatile
unsigned
int
APB1ENR;
volatile
unsigned
int
BDCR;
volatile
unsigned
int
CSR;
} RCC_TypeDef;
#define RCC ((RCC_TypeDef *)0x40021000)
//定义typedef类型别名
typedef
struct
{
volatile
unsigned
int
CRL;
volatile
unsigned
int
CRH;
volatile
unsigned
int
IDR;
volatile
unsigned
int
ODR;
volatile
unsigned
int
BSRR;
volatile
unsigned
int
BRR;
volatile
unsigned
int
LCKR;
} GPIO_TypeDef;
//GPIOA指向地址GPIOA_BASE,GPIOA_BASE地址存放的数据类型为GPIO_TypeDef
#define GPIOA ((GPIO_TypeDef *)GPIOA_BASE)
void
LEDInit( void )
{
RCC->APB2ENR|=1<<2;
//GPIOA 时钟开启
GPIOA->CRH&=0XFFFFFFF0;
GPIOA->CRH|=0X00000003;
}
//粗略延时
void
delay( int
t)
{
unsigned
int
i,n;
for (n=0;n<t;n++)
for (i=0;i<800;i++);
}
int main(void)
{
LEDInit();
while (1)
{
LED0=0;//LED熄灭
delay(500);//延时时间
LED0=1;//LED亮
delay(500);//延时时间
}
}
2. 电路链接以及烧录这里我使用的时STM32最小开发板和USB转TTL串口模块电路连接如下然后打开我们的烧录程序然后查看结果VID_20230924_184345(三)嵌入式C程序中的register和volatile1.register寄存器比内存访问要快,因此可以使用register关键字将C程序中最常用的变量放入寄存器中。关键字register会向编译器提示可以将给定变量放入寄存器中。编译器可以选择是否将其保存在寄存器中。通常,编译器自己进行优化,然后将变量放入寄存器中。示例#include<stdio.h>
int main() { int i = 10;
register int* a = &i;
printf("%d", *a);
getchar();
return 0; }
2.volatilevolatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,告诉编译器对该变量不做优化,都会直接从变量内存地址中读取数据,从而可以提供对特殊地址的稳定访问。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。示例long square(volatile int*ptr)
{
int a;
a = *ptr;
return a * a;
}
(四)总结这次实验中我学到了有关51单片机和STM32有关的知识,学会了使用Keil和Protues来尽心仿真。在实验中我能明显的感受到51单片机的编程要比STM32简单不少,究其原因我觉得首先51单片机的结构比STM32简单,其次就是51单片机的开发环境和工具比较成熟,有很多支持它的软件和硬件工具,而STM32这没有这么丰富的资源,很多东西都需要自己去琢磨和学习,然后就是51单片机的输入输出比较简单,而STM32的GPIO就需要借助复杂的库函数和配置文件。比较嵌入式C程序代码对内存中的各变量的修改操作对比外部对设备的操作。它们的相同点是都需要使用相关的寄存器或地址来访问和修改数据,需要考虑数据的精确性和正确性,要避免出错的情况。它们的不同点是对内存变量进行修改时,C代码可以直接通过变量名来进行更改,而外部设备需要特定的寄存器进行读写,而且对内存中的变量的修改操作主要受限于内存容量,而外部设施的操作受限于设备的特性和功能。

我要回帖

更多关于 单片机模拟仿真软件 的文章

 

随机推荐