3. STM32-GPIO初探

Open Drain (漏极开路)与 push-pull(推挽) 介绍

  1. Open Drain 输出为开路,使用时须加上上拉电阻,输出电压由外部决定。
    https://ithelp.ithome.com.tw/upload/images/20220308/20146325DVTQamUtzN.png
  2. push-pull可以理解为既可以推也可以拉,所以就不需要再加上外部元件了~图中可以看到当输出为高电位时,上方 的电晶体导通而下方的关闭,所以输出为高电位,低电位则两者相反故无需加上上拉电阻。
    https://ithelp.ithome.com.tw/upload/images/20220308/20146325rWUGbQxqs5.png

IDE中的GPIO设定介绍

在STM32CubbeIDE中要设定GPIO相对来的容易~一样点开.ioc档可以去对各个脚位去做设定。
https://ithelp.ithome.com.tw/upload/images/20220308/201463258sKIR3R9Mz.png
在这边我将PB4-PB8设定为GPIO_Output,首先点选PB4将它设为GPIO_Output,其余的脚位同样设定。
https://ithelp.ithome.com.tw/upload/images/20220308/20146325zXRyITlXZt.png
接下来点击左侧的SystemCore当中的GPIO再点选脚位,可以设定GPIO的相关功能。这边介绍一下下方选项的代表意思。

  1. GPIO output level: 用来设定脚位的初始输出为高电位还是低电位
  2. GPIO Mode: 这就是前面所提到的Open Drain 与 Push-pull的设定
  3. GPIO Pull-up / Pull-down:这选项主要是针对输入模式,一般如果是输出选择no-pull,如果是输入的话就要看实际应用的默认输出值是0还是1,假如是输入0就配置为pull-down,输入1为pull-up。
  4. Maximum output speed:有分为Low、High,主要是控制电压转换速率,简单来说就是方波电压由波谷上升到波峰的主要时间。
  5. User Label :可以自行设定脚位的名称方便区分。
    https://ithelp.ithome.com.tw/upload/images/20220308/20146325LvjCAqxng3.png
    当设定完成後记得按下Ctrl+S来储存刚刚所做的设定,这时IDE会自动生成相关的GPIO函数。

GPIO相关函数介绍与暂存器

在透过上方.ioc档中设定完成後除了相关GPIO函数IDE会自动设定完成外,GPIO的暂存器也会配置好。在STM32当中GPIO有6个暂存器CRL、CRH、IDR、ODR、BRSS、BRR,CRL与CRH主要用来表示GPIO的状态一共有32bit,这部分会由IDE设置好。
CRL/CRH Register :CRL控制低8位元 CRH则负责控制高8位元
https://ithelp.ithome.com.tw/upload/images/20220308/20146325FvXUNb004d.png
IDR Register:主要控制IO的输入电位情形,一共有32bit但这边只使用了低16位,高16位保留。要注意的是这个暂存器只能读而已~
https://ithelp.ithome.com.tw/upload/images/20220308/20146325XsLRPZOtpr.png
ODR Register: 主要为控制IO输出电位情形,同样一共有32bit只使用低16位,对这个暂存器写可以直接控制GPIO输出状况。(在这里使用左移的方式会改变暂存器当中所有的值,与BSRR不同的是假设 1<<1 会变成00000011,而ODR则会变成00000010)
https://ithelp.ithome.com.tw/upload/images/20220308/201463252Mn86iY8ii.png
BSRR Register:用来做完IO位设置或是清除的暂存器,简单来说就是用来设置GPIO输出位是1还是0。如果想如果设置GPIOA_1的值为1,则要对BSRR低16位写入即可。
https://ithelp.ithome.com.tw/upload/images/20220308/20146325xtLO1IUhJl.png

GPIOA->BSRR = 1<<1;  //00000001 << 1 = 00000010

同样的如果想要设置GPIOA_1为0,则往高16位写入1即可。

GPIOA->BSRR =  1 << (16+1) //00000001 经过左移16+1位後会在bit17

BRR Register:为GPIO清除Register,作用跟上方BSRR的高16位元类似。
https://ithelp.ithome.com.tw/upload/images/20220308/20146325Abn9Lk5jM6.png

上方所说的是直接透过暂存器对GPIO去做操作,那有没有更好用的方法?当然有!接下来要介绍的是HAL库,可以在左侧专案面板当中的Drivers当中STM32xxxxx_HAL_Driver中找到,里面有各式HAL库所提供的函数!那要怎麽使用HAL库所提供的函数去控制GPIO脚位呢?这边先介绍几个函数~
1. HAL_GPIO_WritePin这函数用来设置脚位是1 or 0

HAL_GPIO_WritePin(GPIOx, GPIO_Pin, PinState);

函数应用

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET); //将脚位设定为高电位
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET); //将脚位设定为低电位

2. HAL_GPIO_ReadPin这函数用来读取脚位是1 or 0

HAL_GPIO_ReadPin(GPIOx, GPIO_Pin);

函数应用

HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5); //读取GPIOA_5

3. HAL_GPIO_TogglePin这函数可以理解为相反输出 也就是说假设原先设定为1则下次会输出0,每一次的输出都与现在输出相反。

HAL_GPIO_TogglePin(GPIOx, GPIO_Pin);

函数应用

HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);//与当前输出相反

接下来另外介绍一个Delay函数,单位为毫秒。
4. HAL_Delay

HAL_Delay(1000);//1000ms = 1s

上面所介绍的函数可以相互组合来控制LED灯的明亮变化~

首先可以先查询一下Datasheet,我这块板子为L746RG在当中有写到板载LED灯LD2脚位为PA5,我们可以利用WritePin与ReadPin去对他读取值。
https://ithelp.ithome.com.tw/upload/images/20220308/20146325B9LlchYobN.png

while(1)
{
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
	State = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5);
	HAL_Delay(500); //0.5s
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
	State = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5);
	HAL_Delay(500); //0.5s
}

记得要在全域变数的位置宣告State,接着在编译後可以在现场表达式当中输入State就可以看到PA5的变化~

接下来介绍另外一种控制方式,透过上面所说的暂存器去控制GPIO的变化!
GPIO的设定照上方的PB4-PB8去做设定,皆为Output!
透过BSRR去将脚位输出设为1,接着透过BRR去将脚位清0,一样可以实现跑马灯的效果!
如果手边没有多余的LED的话可以透过像下方设定全域变数PB_1-PB_5的方式,接着透过现场表达式来观看输出的变化!

while(1)
{
		int i;
	  for(i=0;i<5;i++)
	  {
		  GPIOB->BSRR = (16<<i);

		  HAL_Delay(1000);
		  PB_1 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4);
		  PB_2 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5);
		  PB_3 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6);
		  PB_4 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7);
		  PB_5 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8);
	  }
	  for(i=0;i<5;i++)
	  {
	  	GPIOB->BRR = (16<<i);

	  	HAL_Delay(1000);
	  	PB_1 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4);
	  	PB_2 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5);
	  	PB_3 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6);
	  	PB_4 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7);
	  	PB_5 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8);
	  }
}


上方程序码当中可以看到GPIOB→BSRR = (16<<i),16的计算方式可以对应上方BSRR暂存器来看,16转二进位表示方式为00010000,对应到暂存器可以看到1的位置刚好是PB4,透过左移的方式可以陆续将PB5-8也设为1,BRR也是同理!


<<:  2. STM32-STM32CubeIDE 介面导览/编译

>>:  【JavaScript】阵列方法之filter()

[Day31]C# 鸡础观念- 结语

为什麽会想报名鸭? 这是第一次参加铁人赛, 会参加的原因都是一时冲动,真的是一时冲动,就报名下去了,...

Day0 前言+碎念(可跳过

嗨~大家好!! 我是饿麟,你们也可以叫我小饿 今天是铁人赛开赛的第1天 身为一个小白,我正思考着也许...

D15 - 转移资料到TiDB工具介绍(二)

接下来改用DM来试试看,首先一样先透过tiup安装DM。 tiup install dm 产生拓墣的...

[DAY 06] 盐水爱河 春天小栈

盐水爱河 春天小栈 地点:盐水区西门路7-1号 时间:11:00~22:00 还记得当时会找到这一家...

Day 8 ROS Client Library 与 Roscpp

ROS Client Library ROS 最为一款广为人知的机器人作业系统,当然也能让很多种程序...