一、新建工程

1、工程命名

2、选择工程存储位置

3、默认下一步

4、默认下一步

5、选择没有固件项目,下一步

二、器件放置并连线

1、点击左边工具栏中运放的形状的符号

2、再点击‘P’,搜索器件

3、搜索器件并放置连线

按键控制LED需要的器件有,按键、电容、LED、电阻、主控,LCD1602显示屏,主控选择的是stm32f103r6。

4、器件连线,如下图所示:

图中使用了网络标签,网络标签是在电源、GND的那个工具栏中的DEFAULT。

三、网络配置

1、想要仿真成功运行,首先配置主控参数,双击主控,选择Program File,即代码的hex文件路径,以及Crystal Frequency,即晶振的频率8M,具体如下图所示:

2、仿真供电网络的配置,点击工具栏中的“design”,再点击配置供电网络(点击design后的第四个选项),将"VDDA"增加到"VCC/VDD"中,将"VSSA"增加到"GND"中,如下图所示:

四、代码分享

1、LCD.c代码

#include "stm32f10x.h"                  // Device header
#include "LCD1602.h"


void LCD1602_PORT_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx,ENABLE);	 //使能PC端口时钟	
	GPIO_InitStructure.GPIO_Pin = GPIOx_Pin;				               //端口配置 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		   //推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;		         //IO口速度为10MHz
  GPIO_Init(GPIOx, &GPIO_InitStructure);					               //根据设定参数初始化
}



void delay_nus(uint16_t n)//微妙级延时,通常情况此函数可以不用更改
{
  uint16_t i;
  while(n--)
  {
    i=20;
    while(i--);
  }
}




void delay_nms(uint16_t n) //毫秒级延时,保通常情况此函数可以不用更改
{
    while(n--)
      delay_nus(1100);
}

void LCD_init(void) //初始化,通常情况此函数可以不用更改
{
		LCD1602_PORT_Init(); //LCD 1602使用的PC口初始化
    LCD_RS_0;
    LCD_RW_0; 
    LCD_EN_0; 

    delay_nms(5);
    LCD_cmd(0x38);//16*2显示,5*7点阵,8数据
    delay_nms(1);
    LCD_cmd(0x38);//16*2显示,5*7点阵,8数据
    delay_nms(1);
    LCD_cmd(0x38);//16*2显示,5*7点阵,8数据
    delay_nms(1);
    LCD_cmd(0x08);//先关显示,后开显示
    delay_nms(1);
    LCD_cmd(0x01);//清屏
    delay_nms(1);
    LCD_cmd(0x06);//写命令,注意
    delay_nms(1);   
    LCD_cmd(0x0c);//显示开,关光标
    delay_nms(1);
}

void LCD_clr(void)  //清屏
{
    LCD_cmd(0x01);
}

void LCD_cmd(uint16_t cmd)//写命令
{   
		LCD_RS_0;        
		delay_nus(1);   
		LCD_RW_0;     
		delay_nus(1);   
		LCD_EN_0;      
		delay_nus(1);
		GPIO_SetBits(LCDPORT, LCD_DATA_PORT & cmd);
		GPIO_ResetBits(LCDPORT, LCD_DATA_PORT &(~cmd));
		LCD_EN_1;
		delay_nus(1);    
		LCD_EN_0;     
}

void LCD_dat(uint8_t dat)//写数据
{
    delay_nms(1);   
    LCD_RS_1;
    delay_nus(1);  		 
    LCD_RW_0;       	       
    delay_nus(1);
    LCD_EN_0;                  
    delay_nus(1);
		GPIO_SetBits(LCDPORT, LCD_DATA_PORT & dat);
		GPIO_ResetBits(LCDPORT, LCD_DATA_PORT &(~dat));

    LCD_EN_1;       	   
    delay_nus(1);   
    LCD_EN_0;       	 
}

//写字符串

 void LCD_Write_String(uint8_t x,uint8_t y,uint8_t *s) 
{     
  if (y == 0) 
 	{     
	   LCD_cmd(0x80 + x);     //第一行
 	}
                  
                  else 
 	{      
 	   LCD_cmd(0xC0 + x);      //第二行
 	} 
                  
                  
                 while (*s) 
 	{     
                     LCD_dat( *s);     
                      s ++;     
 	}
 }
//写字符

void LCD_Write_Char(uint8_t x,uint8_t y,uint8_t Data) 
{     
                  if (y == 0) 
 	{     
                    LCD_cmd(0x80 + x);     
 	}    
                  else 
 	{     
                      LCD_cmd(0xC0 + x);     
 	}        
                    LCD_dat( Data);  
}



void LCD_pos(uint16_t x,uint16_t y)//显示位置,不需要修改
{
     if(y)
     LCD_cmd(x | 0xc0);
   	 else
     LCD_cmd(x | 0x80);
}

void LCD_printc(uint16_t x,uint16_t y,uint8_t c)//显示字符,不需要修改
{
    LCD_pos(x,y);
    LCD_dat(c);
}

void LCD_prints(uint16_t x,uint16_t y,uint8_t *s)//显示字符串,不需要修改
{
    LCD_pos(x,y);
    while(*s!='\0')
    {
        LCD_dat(*s);
        s++;
        //delay_nms(1);
    }
}

2、LCD.h代码

#ifndef __LCD1602_H
#define __LCD1602_H



/***********端口定义**********************************************************/
/*#define rs  GPIOSetValue(PORT2,0,rs)
#define rw  GPIOSetValue(PORT2,1,rw)
#define e   GPIOSetValue(PORT2,2,e)
*/

#define  LCDPORT         GPIOC


#define  RS_PIN          GPIO_Pin_8
#define  RW_PIN          GPIO_Pin_9
#define  EN_PIN          GPIO_Pin_10

#define GPIOx            GPIOC 
#define RCC_APB2Periph_GPIOx            RCC_APB2Periph_GPIOC 
#define GPIOx_Pin        GPIO_Pin_All 
#define LCD_DATA_PORT    0xff



#define LCD_RS_1 GPIO_SetBits(LCDPORT, RS_PIN) 		
#define LCD_RS_0 GPIO_ResetBits(LCDPORT, RS_PIN)
#define LCD_RW_1 GPIO_SetBits(LCDPORT, RW_PIN)		
#define LCD_RW_0 GPIO_ResetBits(LCDPORT, RW_PIN)
#define LCD_EN_1 GPIO_SetBits(LCDPORT, EN_PIN)	
#define LCD_EN_0 GPIO_ResetBits(LCDPORT, EN_PIN)






void LCD1602_PORT_Init(void);

void LCD_init(void);			        
void LCD_clr(void);			        
void LCD_cmd(uint16_t cmd);		        
void LCD_dat(uint8_t dat);		        
void LCD_pos(uint16_t x,uint16_t y);	
void LCD_Write_Char(uint8_t x,uint8_t y,uint8_t Data) ;
void LCD_printc(uint16_t x,uint16_t y,uint8_t c);	
void LCD_prints(uint16_t x,uint16_t y,uint8_t *s);	
extern void delay_nus(uint16_t us);	        
extern void delay_nms(uint16_t ms);	  

 void LCD_Write_String(uint8_t x,uint8_t y,uint8_t *s) ;
#endif

3、定时器代码

#include "stm32f10x.h"                  // Device header

/**
  * 函    数:定时中断初始化
  * 参    数:无
  * 返 回 值:无
  */
void Timer_Init(void)
{
	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟
	
	/*配置时钟源*/
	TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
	
	/*时基单元初始化*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		//时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	//计数器模式,选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;				//计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;				//预分频器,即PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;			//重复计数器,高级定时器才会用到
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);				//将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元	
	
	/*中断输出配置*/
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);						//清除定时器更新标志位
																//TIM_TimeBaseInit函数末尾,手动产生了更新事件
																//若不清除此标志位,则开启中断后,会立刻进入一次中断
																//如果不介意此问题,则不清除此标志位也可
	
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);					//开启TIM2的更新中断
	
	/*NVIC中断分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2
																//即抢占优先级范围:0~3,响应优先级范围:0~3
																//此分组配置在整个工程中仅需调用一次
																//若有多个中断,可以把此代码放在main函数内,while循环之前
																//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
	
	/*NVIC配置*/
	NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;				//选择配置NVIC的TIM2线
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	//指定NVIC线路的抢占优先级为2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1
	NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设
	
	/*TIM使能*/
	TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}

/* 定时器中断函数,可以复制到使用它的地方
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}
*/

4、main函数代码

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"
#include "LCD1602.h"
#include "stdint.h"
#include "stdio.h"
#include "stm32f10x_conf.h"
#include "Timer.h"

/****全局变量******************************************/
uint8_t lcd_dat1[20];//液晶第一行
uint8_t lcd_dat2[20];//液晶第二行

uint16_t temp=0;

int main(void)
{
	Timer_Init();//定时器初始化
	LCD_init();    //LCD1602初始化
	LCD_clr();//LCD清屏幕	

	while (1)
	{
		sprintf(lcd_dat1,"%d",temp);
		LCD_prints(0,0,lcd_dat1);//液晶显示第一行

	}
}

/**
  * 函    数:TIM2中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异,否则中断函数将不能进入
  */
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)		//判断是否是TIM2的更新事件触发的中断
	{
		temp++;												//temp变量自增,用于测试定时中断
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);			//清除TIM2更新事件的中断标志位
															//中断标志位必须清除
															//否则中断将连续不断地触发,导致主程序卡死
	}
}


main函数实现了LCD显示数字,并且数字以1s时间自增。

五、仿真与实物不同之处

1、仿真不需要晶振电路

更多推荐