一、新建工程
1、工程命名
2、选择工程存储位置
3、默认下一步
4、默认下一步
5、选择没有固件项目,下一步
二、器件放置并连线
1、点击左边工具栏中运放的形状的符号
2、再点击‘P’,搜索器件
3、搜索器件并放置连线
按键控制LED需要的器件有,按键、电容、LED、电阻、主控,主控选择的是stm32f103r6。
4、器件连线,如下图所示:
图中使用了网络标签,网络标签是在电源、GND的那个工具栏中的DEFAULT。
三、网络配置
1、想要仿真成功运行,首先配置主控参数,双击主控,选择Program File,即代码的hex文件路径,以及Crystal Frequency,即晶振的频率8M,具体如下图所示:
2、仿真供电网络的配置,点击工具栏中的“design”,再点击配置供电网络(点击design后的第四个选项),将"VDDA"增加到"VCC/VDD"中,将"VSSA"增加到"GND"中,如下图所示:
四、代码分享
1、LED代码
#include "stm32f10x.h" // Device header
/**
* 函 数:LED初始化
* 参 数:无
* 返 回 值:无
*/
void LED_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_0|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7 ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA1和PA2引脚初始化为推挽输出
/*设置GPIO初始化后的默认电平*/
GPIO_SetBits(GPIOA, GPIO_Pin_1|GPIO_Pin_0|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); //设置PA1和PA2引脚为高电平
}
/**
* 函 数:LED1开启
* 参 数:无
* 返 回 值:无
*/
void LED1_ON(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1); //设置PA1引脚为低电平
}
/**
* 函 数:LED1关闭
* 参 数:无
* 返 回 值:无
*/
void LED1_OFF(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_1); //设置PA1引脚为高电平
}
/**
* 函 数:LED1状态翻转
* 参 数:无
* 返 回 值:无
*/
void LED1_Turn(void)
{
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0) //获取输出寄存器的状态,如果当前引脚输出低电平
{
GPIO_SetBits(GPIOA, GPIO_Pin_1); //则设置PA1引脚为高电平
}
else //否则,即当前引脚输出高电平
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1); //则设置PA1引脚为低电平
}
}
2、按键代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
/**
* 函 数:按键初始化
* 参 数:无
* 返 回 值:无
*/
void Key_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB1和PB11引脚初始化为上拉输入
}
/**
* 函 数:按键获取键码
* 参 数:无
* 返 回 值:按下按键的键码值,范围:0~2,返回0代表没有按键按下
* 注意事项:此函数是阻塞式操作,当按键按住不放时,函数会卡住,直到按键松手
*/
uint8_t Key_GetNum(void)
{
uint8_t KeyNum = 0; //定义变量,默认键码值为0
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0) //读PB1输入寄存器的状态,如果为0,则代表按键1按下
{
Delay_ms(20); //延时消抖
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)==0 ); //等待按键松手
// Delay_ms(20); //延时消抖
KeyNum = 1; //置键码为1
}
return KeyNum; //返回键码值,如果没有按键按下,所有if都不成立,则键码为默认值0
}
3、main函数代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"
uint8_t KeyNum=0;
uint8_t flag=0;//流水灯方向
uint16_t LED_Value=0x0001;//GPIOA总共是16个IO口 ,二进制0000 0000 0000 0001,代表PA0为高电平,右边是高位,左边低位
int main(void)
{
LED_Init();
Key_Init();
while (1)
{
KeyNum=Key_GetNum();
if(KeyNum==1)//按键切换流水灯的方向
{
if(flag==0)
{
flag=1;
}
else flag=0;
}
//当flag=0时,流水灯方向从A0-A7
if(flag==0)
{
// 输出当前LED值
GPIO_Write(GPIOA, ~LED_Value);//因为IO口为低电平时,灯才亮,于是给GPIOA的寄存器赋值的时候取反。
// 延时
// 左移一位,实现流水灯效果
LED_Value <<= 1;
// 如果左移后的值为0,表示已经移到最高位,重新从最低位开始
if(LED_Value == 0x0100) {
LED_Value = 0x0001;//0000 0000 0000 0001
}
}
//当flag=1时,流水灯方向从A7-A0
if(flag==1)
{
// 输出当前LED值
GPIO_Write(GPIOA, ~LED_Value);//因为IO口为低电平时,灯才亮,于是给GPIOA的寄存器赋值的时候取反。
// 延时
// 右移一位,实现流水灯效果
LED_Value >>= 1;
// 如果左移后的值为0,表示已经移到最低位,重新从最高位PA7开始
if(LED_Value == 0x0000) {
LED_Value = 0x0080;//0000 0000 1000 0000
}
}
Delay_s(100);
}
}
main函数实现了按键控制流水灯的方向,定义了一个变量flag来控制流水灯的方向,按键按下可以对flag的值进行取反。LED的流水灯是通过GPIO的寄存器的值来左移右移实现流水灯的效果,具体看代码注释
五、仿真与实物不同之处
1、仿真的按键引脚需要外部电路上拉
2、仿真不需要晶振电路
3、仿真流水灯的延时不太准确,不知道是不是我电脑CPU仿真不行的原因。