一. 硬软件准备
1. 硬件
此次实验使用串口下载的方式。
-
STM32最小系统核心板(STM32F103C8T6)
-
USB转TTL模块 CH340
-
面包板
-
LED灯
-
若干杜邦线(公对公、公对母、母对母)
2. 软件
- keil5 MDK
- mcuisp 烧录软件
- CH340驱动
二. 编程思想
1. 创建工程
打开Keil,新建工程。选择设备 STM32F10C8
使用寄存器方式开发无需在线添加库文件,直接跳过。
2. 添加文件
在新建工程目录下添加三个文件
- startup_stm32f10x_md.s
启动文件,系统上电后第一个运行的程序,由汇编编写。从固件库里面拷贝而来,由官方提供。
官方固件库下载:STSW-STM32054 - STM32F10x标准外设库 - STMicroelectronics
文件目录:STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\start up\arm\startup_stm32f10x_hd.s
- stm32f10x.h
用户手动新建,用于存放寄存器映射的代码,暂时为空
- main.c
用户手动新建,用于存放 main 函数,暂时为空
3. 编写代码
此次实验选用 GPIOA、GPIOB、GPIOC 三个端口
- 编写 stm32f10x.h
#ifndef _STM32F10X_H_
#define _STM32F10X_H_
/*片上外设基地址 */
#define PERIPH_BASE ((unsigned int)0x40000000)
/*总线基地址,GPIO 都挂载到 APB2 上 */
#define APB1PERIPH_BASE PERIPH_BASE //APB1总线基地址
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) //APB2总线基地址
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000) //AHB 总线基地址
/*GPIOA 外设基地址*/
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
/* GPIOA 寄存器地址,强制转换成指针 */
#define GPIOA_CRL *(unsigned int*)(GPIOA_BASE+0x00) //端口配置低寄存器
#define GPIOA_ODR *(unsigned int*)(GPIOA_BASE+0x0C) //端口输出数据寄存器
/*GPIOB 外设基地址*/
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
/* GPIOB 寄存器地址,强制转换成指针 */
#define GPIOB_CRL *(unsigned int*)(GPIOB_BASE+0x00) //端口配置低寄存器
#define GPIOB_ODR *(unsigned int*)(GPIOB_BASE+0x0C) //端口输出数据寄存器
/*GPIOC 外设基地址*/
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
/* GPIOC 寄存器地址,强制转换成指针 */
#define GPIOC_CRH *(unsigned int*)(GPIOC_BASE+0x04) //端口配置高寄存器
#define GPIOC_ODR *(unsigned int*)(GPIOC_BASE+0x0C) //端口输出数据寄存器
/*RCC 外设基地址*/
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
/*RCC 的 AHB1 时钟使能寄存器地址,强制转换成指针*/
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE+0x18)
#endif
- 编写main.c
选用 A0、B0、C13端口
#include "stm32f10x.h"
void SystemInit(void);
void delay(volatile unsigned int nCount); // volatile 必须要
int main(void)
{
// 开启端口时钟
RCC_APB2ENR |= (1<<2); //GPIOA
RCC_APB2ENR |= (1<<3); //GPIOB
RCC_APB2ENR |= (1<<4); //GPIOC
//清空控制 PA0 的端口位
GPIOA_CRL &= ~(unsigned int)( 0x0F<< (4*0));
//清空控制 PB0 的端口位
GPIOB_CRL &= ~(unsigned int)( 0x0F<< (4*0));
//清空控制 PC13 的端口位
GPIOC_CRH &= ~(unsigned int)( 0x0F<< (4*5));
// 配置 PA0 为通用推挽输出,速度为 10M
GPIOA_CRL |= (1<<4*0);
// 配置 PB0 为通用推挽输出,速度为 10M
GPIOB_CRL |= (1<<4*0);
// 配置 PC13 为通用推挽输出,速度为 10M
GPIOC_CRH |= (1<<4*5);
while (1)
{
GPIOA_BSRR=0x00000001; //置1
delay(0xFFFFF);
GPIOA_BRR=0x00000001; //清0
GPIOB_BSRR=0x00000001;
delay(0xFFFFF);
GPIOB_BRR=0x00000001;
GPIOC_BSRR=0x00008000;
delay(0xFFFFF);
GPIOC_BRR=0x00008000;
}
}
// 函数为空,目的是为了骗过编译器不报错
void SystemInit(void)
{
}
//延时函数
void delay(volatile unsigned int nCount) // volatile 必须要
{
for (; nCount != 0; nCount--);
}
延时函数中,volatile 必须加上,否则无效
volatile 的作用就是指示编译器不要因优化而省略此指令,必须每次都直接读写其值。
4. 编译设置
- 点击方框内的魔法棒
路径有中文的这种习惯一定要改。这里有中文是因为课程实验原因,用中文方便分类。
- 点击Output,勾选 hex文件。此文件就是用来烧进芯片内的。
- 勾选Use Simulator 使用软件调试。更改 Dialog DLL 以及 Parameter
Dialog DLL 设置为 DARMSTM.DLL 和 TARMSTM.DLL
Parameter 都设置为 -pSTM32F103C8
现在就可以编译了
编译无误
三. 软件调试
- 点击方框内,开始调试
- 打开 logic analyzer窗口,进行波形分析
- 点击 Setup 选项
- 点击方框 新建
我使用了A0、B0、C13 端口
新建三个并分别填写三个端口:GPIOA_ODR.0 GPIOB_ODR.0 GPIOC_ODR.13
- 类型都设置为比特流。并可以选择设置各个波形颜色。
设置完就可以点击下方 Close 退出了
- 点击方框内 run开始
- 查看波形
四. 硬件调试
- 安装 CH340 驱动
蓝奏云链接:https://diyugreat.lanzouw.com/iYEvFvmh1xe 密码:3oib
若安装失败,自行去寻找答案
- 下载mcuisp烧录软件。无需安装,直接使用。
蓝奏云链接:https://diyugreat.lanzouw.com/ita3nvmh1yf 密码:e1d2
- stm32核心板与usb转TTL模块的接线
- boot0接1,boot1接0。因为要用串口烧录程序
- 总体接线
五. 最终效果
如果延时函数没有加上 volatile 那么效果就是如图所示。
是不是看到全亮,对,你没看错。这是我用别人核心板烧录的程序,因为我自己的核心板后面被我玩坏了,进入锁死状态了,因此用了别人的。最终的效果就是如此,三个灯常亮。与调试的波形的完全不同。
加上 volatile 后,成功
六. 总结
寄存器方式操控,容易出问题,且出了问题不好找,寄存器方式还是少用吧,还是使用标准库或者抽象库开发更好。
抽象库开发可以查看我的另一篇博客:
STM32F103 + STM32CubeMX实现流水灯闪烁_diyu-CSDN博客
七. 参考资料
-
《零死角玩转STM32—F103指南者》pdf版
-
c8t6 datasheet.pdf(芯片手册)
-
STM32F10x参考手册.pdf(中文版)
-
STM32固件库使用手册的中文翻译版.pdf
资料蓝奏云链接: