MDK 开发环境与 Proteus 仿真软件(8个led循环点亮
1、新建项目
利用库文件构建
型号:STM32F103R6
- 库函数下载
[https://pan.baidu.com/s/1l02hIqlM-L4AKW0pWZ2-hA?pwd=1c46]
- 新建项目文件,如:Demo1_LedTest
- 在该文件夹下分别新建Doc、FWLib、Driver、Project、Startup、User文件夹
- 说明
文件名 | 存放文件 |
---|---|
Doc | 说明书,程序功能、版本、修改记录 |
FWLib | 库函数及核函数 |
Driver | 各个接口的初始化文件及头文件、启动代码 |
Project | 工程项目名称、输出 |
Startup | 启动配置文件 |
User | 主程序及应用程序 |
-
新建一个工程到Project文件夹下
-
在工程文件夹内几个文件夹:User、Project、Doc、Drivers、Libraries
2、绘制仿真图
3、程序流程图
- 主程序流程图
- 子程序流程图
4、编写主程序和程序
主程序main.c
#include "stm32f10x.h"
#include "bsp_led.h"
#include "delay.h"
int main(void)
{
/*定义变量*/
/*初始化硬件接口*/
led_init_all(); //初始化与 LED 连接的硬件接口
while(1)
{
led_on(LED0);
delay_ms(20);
led_off(LED0);
delay_ms(20);
led_on(LED1);
delay_ms(20);
led_off(LED1);
delay_ms(20);
led_on(LED2);
delay_ms(20);
led_off(LED2);
delay_ms(20);
led_on(LED3);
delay_ms(20);
led_off(LED3);
delay_ms(20);
led_on(LED4);
delay_ms(20);
led_off(LED4);
delay_ms(20);
led_on(LED5);
delay_ms(20);
led_off(LED5);
delay_ms(20);
led_on(LED6);
delay_ms(20);
led_off(LED6);
delay_ms(20);
led_on(LED7);
delay_ms(20);
led_off(LED7);
delay_ms(20);
}
}
子程序bsp_led.h
#ifndef __BSP_LED_H
#define __BSP_LED_H
#include "stm32f10x.h"
/// LED硬件配置
#define LED_NUM 8 ///< 设置LED的数量, 该驱动最多允许16个LED灯
#define LED_LEVEL 0 ///< 0, 低电平点亮LED. 1, 高电平点亮LED
#define LED0_PORT GPIOC /* GPIO端口 */
#define LED0_CLK RCC_APB2Periph_GPIOC /* GPIO端口时钟 */
#define LED0_PIN GPIO_Pin_0 /* 连接到SCL时钟线的GPIO */
#define LED1_PORT GPIOC /* GPIO端口 */
#define LED1_CLK RCC_APB2Periph_GPIOC /* GPIO端口时钟 */
#define LED1_PIN GPIO_Pin_1 /* 连接到SCL时钟线的GPIO */
#define LED2_PORT GPIOC /* GPIO端口 */
#define LED2_CLK RCC_APB2Periph_GPIOC /* GPIO端口时钟 */
#define LED2_PIN GPIO_Pin_2 /* 连接到SCL时钟线的GPIO */
#define LED3_PORT GPIOC /* GPIO端口 */
#define LED3_CLK RCC_APB2Periph_GPIOC /* GPIO端口时钟 */
#define LED3_PIN GPIO_Pin_3 /* 连接到SCL时钟线的GPIO */
#define LED4_PORT GPIOC /* GPIO端口 */
#define LED4_CLK RCC_APB2Periph_GPIOC /* GPIO端口时钟 */
#define LED4_PIN GPIO_Pin_4 /* 连接到SCL时钟线的GPIO */
#define LED5_PORT GPIOC /* GPIO端口 */
#define LED5_CLK RCC_APB2Periph_GPIOC /* GPIO端口时钟 */
#define LED5_PIN GPIO_Pin_5 /* 连接到SCL时钟线的GPIO */
#define LED6_PORT GPIOC /* GPIO端口 */
#define LED6_CLK RCC_APB2Periph_GPIOC /* GPIO端口时钟 */
#define LED6_PIN GPIO_Pin_6 /* 连接到SCL时钟线的GPIO */
#define LED7_PORT GPIOC /* GPIO端口 */
#define LED7_CLK RCC_APB2Periph_GPIOC /* GPIO端口时钟 */
#define LED7_PIN GPIO_Pin_7 /* 连接到SCL时钟线的GPIO */
typedef enum
{
LED0 = 0,
LED1 = 1,
LED2 = 2,
LED3 = 3,
LED4 = 4,
LED5 = 5,
LED6 = 6,
LED7 = 7,
} led_name_t;
void led_init_all(void); // 初始化所有的LED
void led_init(led_name_t led_name); // 初始化指定的LED
void led_on(led_name_t led_name); // LED打开
void led_off(led_name_t led_name); // LED关闭
void led_toggle(led_name_t led_name); // LED翻转
uint8_t led_get_status(led_name_t led_name); // 读取当前LED状态
#endif
子程序bsp_led.c
#include "bsp_led.h"
/// LED参数类型定义
typedef struct
{
GPIO_TypeDef* PORT; ///< LED的PORT口
const uint32_t CLK; ///< LED的时钟模块
const uint16_t PIN; ///< LED的PIN口
} led_para_t;
/// LED参数映射表
static led_para_t led_para[LED_NUM] = {
#if (LED_NUM > 0)
{LED0_PORT, LED0_CLK, LED0_PIN},
#endif
#if (LED_NUM > 1)
{LED1_PORT, LED1_CLK, LED1_PIN},
#endif
#if (LED_NUM > 2)
{LED2_PORT, LED2_CLK, LED2_PIN},
#endif
#if (LED_NUM > 3)
{LED3_PORT, LED3_CLK, LED3_PIN},
#endif
#if (LED_NUM > 4)
{LED4_PORT, LED4_CLK, LED4_PIN},
#endif
#if (LED_NUM > 5)
{LED5_PORT, LED5_CLK, LED5_PIN},
#endif
#if (LED_NUM > 6)
{LED6_PORT, LED6_CLK, LED6_PIN},
#endif
#if (LED_NUM > 7)
{LED7_PORT, LED7_CLK, LED7_PIN},
#endif
};
/// LED IO口初始化, 配置成推挽输出
static __INLINE void led_port_init(led_name_t led_name)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(led_para[led_name].CLK, ENABLE); // 使能LED的时钟
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Pin = led_para[led_name].PIN; // 设置LED的PIN
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // IO口设为推拉输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; // 输出频率最大2MHz,LED应用足矣
GPIO_Init(led_para[led_name].PORT, &GPIO_InitStructure); // 初始化该LED的IO口
}
/// 读取LED IO口电平值
static __INLINE uint32_t LED_PORT_LEVEL(led_name_t led_name)
{
return GPIO_ReadOutputDataBit(led_para[led_name].PORT,led_para[led_name].PIN);
}
/// LED IO口电平置高
static __INLINE void LED_PORT_HIGH(led_name_t led_name)
{
GPIO_SetBits(led_para[led_name].PORT,led_para[led_name].PIN);
}
/// LED IO口电平置低
static __INLINE void LED_PORT_LOW(led_name_t led_name)
{
GPIO_ResetBits(led_para[led_name].PORT,led_para[led_name].PIN);
}
/// LED IO口电平翻转
static __INLINE void LED_PORT_TOGGLE(led_name_t led_name)
{
uint8_t ret;
ret=GPIO_ReadOutputDataBit(led_para[led_name].PORT,led_para[led_name].PIN);
if(ret)
GPIO_ResetBits(led_para[led_name].PORT,led_para[led_name].PIN);
else
GPIO_SetBits(led_para[led_name].PORT,led_para[led_name].PIN);
}
/**
******************************************************************************
* @brief 初始化所有的LED灯
* @param none
* @retval none
******************************************************************************
*/
void led_init_all(void)
{
uint8_t i;
for (i=0; i<LED_NUM; i++)
led_init((led_name_t)i);
}
/**
******************************************************************************
* @brief LED灯初始化
* @param led_name
* @arg 可用值请参考 led_name_t 类型定义中的枚举值
* @retval none
******************************************************************************
*/
void led_init(led_name_t led_name)
{
led_port_init(led_name);
led_off(led_name); // 初始化关闭该LED
}
/**
******************************************************************************
* @brief LED灯打开
* @param led_name
* @arg 可用值请参考 led_name_t 类型定义中的枚举值
* @retval none
******************************************************************************
*/
void led_on(led_name_t led_name)
{
#if (LED_LEVEL > 0)
LED_PORT_HIGH(led_name);
#else
LED_PORT_LOW(led_name);
#endif
}
/**
******************************************************************************
* @brief LED灯关闭
* @param led_name
* @arg 可用值请参考 led_name_t 类型定义中的枚举值
* @retval none
******************************************************************************
*/
void led_off(led_name_t led_name)
{
#if (LED_LEVEL > 0)
LED_PORT_LOW(led_name);
#else
LED_PORT_HIGH(led_name);
#endif
}
/**
******************************************************************************
* @brief LED灯翻转
* @param led_name
* @arg 可用值请参考 led_name_t 类型定义中的枚举值
* @retval none
******************************************************************************
*/
void led_toggle(led_name_t led_name)
{
LED_PORT_TOGGLE(led_name);
}
/**
******************************************************************************
* @brief 查询LED当前状态
* @param led_name
* @arg 可用值请参考 led_name_t 类型定义中的枚举值
* @retval status. LED状态
* @arg 0, LED灯关闭状态
* @arg 1, LED灯打开状态
******************************************************************************
*/
uint8_t led_get_status(led_name_t led_name)
{
if (LED_PORT_LEVEL(led_name)) return 0;
else return 1;
}
/********************************************END OF FILE**********************/
5、 运行仿真
- 方式1:led1亮—延时—led1灭—led2亮—延时—led2灭…
- 方式2:led1亮—延时—led2亮—延时—led3亮—延时…led1灭—延时—led2灭…
6、 遇到的问题及解决措施
-
问题1:cannot open source input file “stm32f10x_adc.h”: No such file or directory.
-
解决:添加头文件所在路径到编译器里,以便编译器可以检索到改头文件。
-
问题2:Not enough information to list load addresses in the image map.
Not enough information to list load addresses in the image map. -
解决:只声明了函数,却未定义函数实体,所以在这个前提下,调用函数时会报这个错误。
解决方法就是:定义函数实体,或者取消函数调用。 -
问题:warning: #223-D: function “delay_ms” declared implicitly.
-
解决:在main.c函数中添加头文件#include “delay.h”
7、总结
- 在第一个构建工程模板时要尽量仔细一些,不要缺少文件。
- 在编写程序过程中应该保持严谨的态度,尽量将程序写的更加合理。
- 遇到报错不要着急,根据报错的信息认真分析可能出错的原因,如果无法解决可以上网搜索相关资料,问题解决后应该做好记录。
- 实验过后认真总结,分析实验过程遇到的问题,养成良好的实验习惯。