stm32真·入门笔记(二)

keil实战——新建工程模板 

新建项目的时候发现没有32的库,还需要自己添加一下,去官网下载,网址:MDK5 Software Packs

野火视频用的是F1

在网址里找到keil这个标题,往下翻

下载即可

 下载完以后双击安装

 装了MDK会自动识别,直接点击NEXT,装完以后点击finish

我是装完才截的图,会有警告,没装过的不会有,忽略警告就好

 新建步骤如图,视频里讲的很清楚,就不细说了

 

 

 

下图直接关闭即可

 添加启动文件,地址如下

A盘(资料盘)\3-STM32官方资料\STM32F103官方固件库与手册(标准库)\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm

把startup_stm32f10x_hd.s复制到工程目录下

复制以后在keil中双击Source Group1,添加此文件到工程里 

在目录里新建txt文件,把名字改为main.c ,以同样的步骤把main添加进工程里,别忘了添加.h文件

 我txt文件无论怎么改名都无法转换成.c文件

解决办法:

这是我在csdn找的http://t.csdn.cn/0DJQy

1、首先你要有C/C++软件,如DEV-C(下载地址如下Dev-C++ download | SourceForge.net)

2、如果你是WIN10系统。首先打开“此电脑”,依次点“查看”-“选项”-“查看”,将“隐藏已知文件类型的扩展名”前面的勾去掉,再确定,让系统显示完整的文件全名。然后.c后缀就能直接改成C文件。

 双击选项

去掉选项以后再进行重命名的操作就可以了

新建项目,编译

此时直接编译的话,会出现如下错误:
“ Error: L6218E: Undefined symbol SystemInit (referred from startup_stm32f429_439xx.o)”
错误提示 SystemInit引用但没有定义。

图 2  汇编文件

由图汇编文件可知,运行的时候会先运行SystemInit,初始化系统时钟以后在调用面函数

在main函数外面做一个空实现,即可解决报错

这块我从一开始就出现了意想不到的问题,

然后就是我明明输的和老师一样吧,SystemInit报错no previous prototype for function systeminit

解决办法:

鼠标右键点击Target 1,选择Options for Group‘Source Group 1...’

或者你发现工具栏里有,和编译在一行,直接点击工具栏里的即可

将 6选成5即可

 

然后还没完呢,现在编译器确实不报错了,但是呢编译不过,会出现以下问题,编译终止

神奇的事情来了,既然Version 5 is not available,我就又换回Version 6了,这次编译页面也没有报错,编译也是直接就过了。

这个问题说一下,我这里装的是keil社区版,不能调试,才会有这种奇怪的现象,如果是破解版的,换成5版本就没有问题了,我后面又装了一个破解版,后续所有例程都是在破解版下进行的了。

1.include<>与include" "区别

 include<>表示文件不在当前目录下,在编译器目录下

 include" "表示在当前目录下找不到,再去软件目录下找

 .hex:通过串口下载的可执行文件

.axf:通过编译器下载的可执行文件

.sct:加载没听清,以后补文件

配置

下载程序

debug里选择DAP

 确保Utilities里的use debug driver是勾选上的

 然后在返回debug,在选择DAP的位置点击setting,在debug界面确保SWJ是勾选上的,时钟选择5MHz

 切换到Flash Download界面,勾选reset and run

 下载即可。如果出现这个报错,重新编译下

 我实际下载的时候发现与视频中不一样,我的无法勾选SWJ,如图

 去问了淘宝客服,说是版本不一样,只需connect处选择under Reset,Reset处选择SYSRESETREQ,,然后再次下载,就能成功了。

2.屏蔽   #if 0

             #else

             # end if

点亮LED灯

点灯三部曲

//  1.打开时钟 在AHB上
//  2.设置输出模式   GPIOx_CRL
//  3.开灯 用CDR设置指定位置为0

步骤

 图 3 指南者原理图

(1)由图可知,PB0控制灯,PB0为0,灯亮

PB0通过GPIOB_ODR第0位控制 

复位值为0x0000 0000,所以低十六位全是0

  *(unsigned int*) (0x40010C0C) & =~(1<<0);利用上一篇最后的清零操作

这一部相当于

(2)显然光有这一步等还是不会亮,这是由于PB0目前是输入状态,不是输出状态,需改变输入状态

此寄存器四位控制一个IO口 ,CRL思维控制的一个io口,相当于ODR寄存器里的pb0

由下方每一位的解释来选择模式,LED一般用推挽输出,所以CNF选择00,MODE选择01(此位置选择没有固定原因,就是随机选择)

*(unsigned int*)0x40010C00 |=((1)<<(4*0));//最后一位置一

这行刚开始代码我一直理解的不太好,找淘宝客服battle半天,后面发现按我的理解完全可以实现视频里的结果,并且作业中的点亮其他灯也完美实现,所以我觉得我的理解没有问题

这里说一下我的理解,确实是像视频里说的一样四个一组,

*(unsigned int*)0x40010C00 |=((1)<<(4*0));这行代码在我这边是这样的

*(unsigned int*)0x40010C00 |=((0x01)<<(4*0));相当于是0001这个整体左移了4个0;

在CRL寄存器里,四位对因一个PBx,如图

所以在程序里我这行代码是这样写的(*(unsigned int*)(0x40010C00))|= ((0x01)<<(0*(4*1)));

(3)加上这一步以后,灯还是不能点亮,这是因为GPIO时钟被关闭

 所以还要将时钟使能

  

可知0时钟关闭,所以要置一,地址为0x40021018,IOPB在第三位,所以左移三位置一

*(unsigned int*)0x40021018 |=(1<<3);

整体代码如下

 作业

作业需要注意的是,灯对应的引脚不一样,其对应的CRL寄存器的位不一样,记得改CRL的值

点灯代码如下

//点亮蓝灯
	//记得改CRL输出端口,不然输出端口一直是PB0,亮什么蓝灯啊
	(*(unsigned int*)(0x40021018))|=(1<<3);
	(*(unsigned int*)(0x40010C00))|= ((0x01)<<(4*1));//配置低寄存器CRL 模式为 0001  PB0的端口
  //(*(unsigned int*)(0x40010C0C)) |=(1<<0); 可以不需要,因为CRL输出端口变了
	(*(unsigned int*)(0x40010C0C)) &=~(1<<1);
	
	
		//点亮红灯
	//打开时钟 APB2 外设时钟使能寄存器(RCC_APB2ENR)
	(*(unsigned int*)(0x40021018))|=(1<<3);
	(*(unsigned int*)(0x40010C00))|= ((0x01)<<(5*(4*1)));//配置低寄存器CRL 模式为 0001  PB1的端口
	(*(unsigned int*)(0x40010C0C)) &=~(1<<5);

延时函数

原因是函数写道main函数以后,并且没在main前声明

void mydelay(int dy)
{
  int i=0;
  int j=0;	
	for(i=0;i<dy;i++)
	{
		for(j=0;j<1000;j++)
		{
			
		}
	}
}

蓝灯闪烁

//蓝灯闪烁
		(*(unsigned int*)(0x40021018))|=(1<<3);
		(*(unsigned int*)(0x40010C00))|= ((0x01)<<(4*1));
		while(k<10){
		
		(*(unsigned int*)(0x40010C0C)) &=~(1<<1);//点蓝灯
		mydelay(500);
	  (*(unsigned int*)(0x40010C0C)) |=(1<<1);//关蓝灯
		mydelay(500);
		k++;
	}

绿蓝红依次闪烁

(*(unsigned int*)(0x40021018))|=(1<<3);
		while(k<10){
		(*(unsigned int*)(0x40010C00))|= ((1)<<(4*0));
		(*(unsigned int*)(0x40010C0C))&=~(1<<0);//点绿灯
		mydelay(500);
		(*(unsigned int*)(0x40010C0C)) |=(1<<0);  //关闭绿灯
		mydelay(500);
		
		(*(unsigned int*)(0x40010C00))|= ((0x01)<<(4*1));
		(*(unsigned int*)(0x40010C0C)) &=~(1<<1);//点蓝灯
		mydelay(500);
	  (*(unsigned int*)(0x40010C0C)) |=(1<<1);//关蓝灯
		mydelay(500);
		
		(*(unsigned int*)(0x40010C00))|= ((0x01)<<(5*(4*1)));
		(*(unsigned int*)(0x40010C0C)) &=~(1<<5);//点红灯
		mydelay(500);
		(*(unsigned int*)(0x40010C0C)) |=(1<<5);//关红灯
		mydelay(500);
		k++;
	}

优化版,在h文件中声明好地址

//基地址
#define PERIPH_BASE      ((unsigned int)0x40000000)

//总线基地址   AHB  APB1  APB2
#define   APB1PERIHP_BASE      PERIPH_BASE                 //((unsigned int)0x40000000)
#define   APB2PERIHP_BASE     (PERIPH_BASE + 0x10000)     //((unsigned int)0x40000000 + 00010000)   
#define   AHBPERIHP_BASE     (PERIPH_BASE + 0x20000)    //AHB前三位为保留,单独定义,从0x20000开始定义

 AHB前两位是保留,所以单独定义这两位,AHB从DAM1开始定义

作业

//外设 perirharl

//基地址
#define PERIPH_BASE      ((unsigned int)0x40000000)

//总线基地址   AHB  APB1  APB2
#define   APB1PERIHP_BASE      PERIPH_BASE                 //((unsigned int)0x40000000)
#define   APB2PERIHP_BASE     (PERIPH_BASE + 0x10000)     //((unsigned int)0x40000000 + 00010000)   
#define   AHBPERIHP_BASE     (PERIPH_BASE + 0x20000)    //AHB前三位为保留,单独定义,从0x20000开始定义

//时钟复位和恢复控制RCC
#define   RCC_BASE       (AHBPERIHP_BASE + 0x1000)  
#define   RCC_APB2ENR       *(unsigned int*)(RCC_BASE + 0x18)

//GPIO 外设基地址 ABCDEFGH
#define   GPIOA_BASE     (APB2PERIHP_BASE + 0x0800)
#define   GPIOB_BASE     (APB2PERIHP_BASE + 0x0C00)
#define   GPIOC_BASE     (APB2PERIHP_BASE + 0x1000)
#define   GPIOD_BASE     (APB2PERIHP_BASE + 0x0400)
#define   GPIOE_BASE     (APB2PERIHP_BASE + 0x1800)
#define   GPIOF_BASE     (APB2PERIHP_BASE + 0x1C00)
#define   GPIOG_BASE     (APB2PERIHP_BASE + 0x2000)

//寄存器地址  GPIOA
#define   GPIOA_CRL      *(unsigned int*)(GPIOA_BASE)
#define   GPIOA_CRH      *(unsigned int*)(GPIOA_BASE + 0x04)   
#define   GPIOA_IDR      *(unsigned int*)(GPIOA_BASE + 0x08)   
#define   GPIOA_ODR      *(unsigned int*)(GPIOA_BASE + 0x0C)   
#define   GPIOA_BSRR     *(unsigned int*)(GPIOA_BASE + 0x10)   
#define   GPIOA_LCKR     *(unsigned int*)(GPIOA_BASE + 0x14) 
 
//寄存器地址  GPIOB
#define   GPIOB_CRL      *(unsigned int*)(GPIOB_BASE)
#define   GPIOB_CRH      *(unsigned int*)(GPIOB_BASE + 0x04)   //(GPIOB_BASE + 0400)
#define   GPIOB_IDR      *(unsigned int*)(GPIOB_BASE + 0x08)   //(GPIOB_BASE + 0800)
#define   GPIOB_ODR      *(unsigned int*)(GPIOB_BASE + 0x0C)   //(GPIOB_BASE + 0C00)
#define   GPIOB_BSRR     *(unsigned int*)(GPIOB_BASE + 0x10)   //(GPIOB_BASE + 1000)
#define   GPIOB_LCKR     *(unsigned int*)(GPIOB_BASE + 0x14)   //(GPIOB_BASE + 1400)

//寄存器地址  GPIOC
#define   GPIOC_CRL      *(unsigned int*)(GPIOC_BASE)
#define   GPIOC_CRH      *(unsigned int*)(GPIOC_BASE + 0x04)   
#define   GPIOC_IDR      *(unsigned int*)(GPIOC_BASE + 0x08)   
#define   GPIOC_ODR      *(unsigned int*)(GPIOC_BASE + 0x0C)   
#define   GPIOC_BSRR     *(unsigned int*)(GPIOC_BASE + 0x10)   
#define   GPIOC_LCKR     *(unsigned int*)(GPIOC_BASE + 0x14) 

//寄存器地址  GPIOD
#define   GPIOD_CRL      *(unsigned int*)(GPIOD_BASE)
#define   GPIOD_CRH      *(unsigned int*)(GPIOD_BASE + 0x04)   
#define   GPIOD_IDR      *(unsigned int*)(GPIOD_BASE + 0x08)   
#define   GPIOD_ODR      *(unsigned int*)(GPIOD_BASE + 0x0C)   
#define   GPIOD_BSRR     *(unsigned int*)(GPIOD_BASE + 0x10)   
#define   GPIOD_LCKR     *(unsigned int*)(GPIOD_BASE + 0x14) 

点灯

 //优化  提升代码可读性
 //打开时钟
 RCC_APB2ENR|=(1<<3);
 //先将CRL清零
 GPIOB_CRL &=~((0x0f)<<(4*0));
 //先设置输出模式  配置低寄存器CRL 模式为 0001
 GPIOB_CRL |= ((1)<<(4*0));
 //ODR设置指定位置为0
 GPIOB_ODR &=~(1<<0);
 //GPIOB_ODR |=(1<<0);  //关闭绿灯
 
 
 //BSRR控制开灯
 //绿灯
 //打开时钟
 RCC_APB2ENR |=(1<<3);
 //先清零
 GPIOB_CRL &=~((0x0f)<<(4*0));
 //设置输出模式
 GPIOB_CRL |=((0x01<<(4*0)));
  //配置BSRR  BSy使对应PBy为1  关灯
 //GPIOB_BSRR |=(1<<0);
 //BRR  BRy使对应PBy为0  点灯
 GPIOB_BRR |=(1<<0);
 
 
 //红灯
 //打开时钟
 RCC_APB2ENR |=(1<<3);
 //先清零
 GPIOB_CRL &=~((0x0f)<<5*(4*1));
 //设置输出模式
 GPIOB_CRL |=((0x01<<5*(4*1)));
  //配置BSRR  BSy使对应PBy为1  关灯
 //GPIOB_BSRR |=(1<<5);
 //BRR  BRy使对应PBy为0  点灯
 GPIOB_BRR |=(1<<5);
 
 
  //蓝灯
 //打开时钟
 RCC_APB2ENR |=(1<<3);
 //先清零
 GPIOB_CRL &=~((0x0f)<<(4*1));
 //设置输出模式
 GPIOB_CRL |=((0x01<<(4*1)));
  //配置BSRR  BSy使对应PBy为1  关灯
 //GPIOB_BSRR |=(1<<1);
 //BRR  BRy使对应PBy为0  点灯
 GPIOB_BRR |=(1<<1);
 
//红灯闪烁
  RCC_APB2ENR |=(1<<3);
  GPIOB_CRL |= ((0x01)<<5*(4*1));
  while(k<10){
  
  GPIOB_BRR |=(1<<5);//点灯
  mydelay(500);
   GPIOB_BSRR |=(1<<5);//关灯
  mydelay(500);
  k++;
 }

//绿蓝红依次点亮
  RCC_APB2ENR |=(1<<3);
  while(k<10){
  GPIOB_CRL|= ((1)<<(4*0));
  GPIOB_BRR |=(1<<0);//点绿灯
  mydelay(500);
  GPIOB_BSRR |=(1<<0);  //关闭绿灯
  mydelay(500);
  
  GPIOB_CRL|= ((0x01)<<(4*1));
  GPIOB_BRR |=(1<<1);//点蓝灯
  mydelay(500);
   GPIOB_BSRR |=(1<<1);//关蓝灯
  mydelay(500);
  
  GPIOB_CRL|= ((0x01)<<(5*(4*1)));
  GPIOB_BRR |=(1<<5);//点红灯
  mydelay(500);
  GPIOB_BSRR |=(1<<5);//关红灯
  mydelay(500);
  k++;
 }

GPIO功能概述

全称:General purpose input output,软件可控制的引脚

 1.GPIO包含在引脚内部

2.查找stm32数据手册

 功能框图

 按照图中顺序来看,虚线部分是芯片内部,我们无法看到。

保护二极管原理,当I/O口输入电压高于3.3v,上方二极管导通

 当电压小于0V,下方二极管导通

 下面进入内部输出部分

开漏和推挽都是通过控制输出数据寄存器高低电平来控制的

这里涉及模电MOS管的知识,我比较清楚,有需要的话后面会加进来。

首先是推挽输出

简化电路分析,当输入是1时,经过反相器,变为0,PMOS导通,NMOS截至,输出电压和VDD相同,输出3.3V电压

 当输入是0时,经过反相器以后变为去,PMOS截至,NMOS管导通,输出处电压被拉为0V

 开漏输出(I2C,MODBus)

 当输入一个高电平,经过反相器,NMOS管截止,需加上拉电阻输出为高电平

 输入为一个低电平时,经过反相器,NMOS管导通,将out拉为低电平,此低电平是内部电路提供的

 

 可以直接通过ODR控制输出,也可以通过BSRR控制

 低16位控制set,置位,让BS0为1,将BS0写为1,

高16位是Reset,清零,让BR0为零,将BR0写为1

同时写1的话,置位起作用

 

 BSR低16位有效,清零,Reset

 复用功能输出,有可能是串口

输入IDR,当通过BSRR或者ODR控制输出1的话,可以通过IDR监测到

上拉输入,下拉输入

在CRL寄存器里,但是是通过软件按控制,不直接配置CRL寄存器

当配置成上拉时,向置位寄存器BSRR里写1;配置下拉时,向BSR里写1

施密特触发器起到门限作用,当电压小于1.2v时为低电平0,高于2.V为高电平1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值