文章目录

  • 一、GPIO的控制
  • 要求:软件仿真,根据高8位pin输入电平,低8位输出相应的电平。写出main.c代码。
  • 编程思路:
  • 方式1:直接读、写输入\输出寄存器。
  • 代码:
  • 方式2:通过位设置\清除寄存器 和 位清除寄存器控制。
  • BSRR位设置\清除寄存器
  • BRR位清除寄存器
  • 代码:
  • 方式3 位绑定
  • 位绑定的定义:
  • 个人理解
  • 代码:
  • 公式代码:
  • 各GPIO位绑定代码块(复制粘贴):
  • 二、stm32库函数


一、GPIO的控制

Windows工控机怎么调用io python 工控机gpio怎么控制_寄存器

要求:软件仿真,根据高8位pin输入电平,低8位输出相应的电平。写出main.c代码。

编程思路:

1、配置模式,P0.0~P0.7推挽输出,P0.8-P0.15浮空输入。
2、输入状态反映到对应引脚输出。

方式1:直接读、写输入\输出寄存器。

Windows工控机怎么调用io python 工控机gpio怎么控制_嵌入式_02

代码:

#include "stm32f10x.h"

int main(void)
{
	//1、配置模式,P0.0~P0.7输出,P0.8-P0.15输入。
	GPIOA->CRL = 0x33333333;//0x00000033前面的零是可以省略的
	GPIOA->CRH = 0x44444444;
	//2、输入状态反映到对应引脚输出。
	while(1)
	{
		if((GPIOA->IDR&0x0100) == 0x0100) 	GPIOA->ODR |= 0x0001;
		else 																GPIOA->ODR &= ~(0x0001);
		
		if((GPIOA->IDR&0x0200) == 0x0200)		GPIOA->ODR |= 0x0002;
		else 																GPIOA->ODR &= ~(0x0002);
		
		if((GPIOA->IDR&0x0400) == 0x0400)		GPIOA->ODR |= 0x0004;
		else 																GPIOA->ODR &= ~(0x0004);
		
		if((GPIOA->IDR&0x0800) == 0x0800)		GPIOA->ODR |= 0x0008;
		else 																GPIOA->ODR &= ~(0x0008);
		if((GPIOA->IDR&0x1000) == 0x1000)		GPIOA->ODR |= 0x0010;
		else 																GPIOA->ODR &= ~(0x0010);
		if((GPIOA->IDR&0x2000) == 0x2000)		GPIOA->ODR |= 0x0020;
		else 																GPIOA->ODR &= ~(0x0020);
		if((GPIOA->IDR&0x4000) == 0x4000)		GPIOA->ODR |= 0x0040;
		else 																GPIOA->ODR &= ~(0x0040);
		if((GPIOA->IDR&0x8000) == 0x8000)		GPIOA->ODR |= 0x0080;
		else 																GPIOA->ODR &= ~(0x0080);
	}
	
	return 0;
}

方式2:通过位设置\清除寄存器 和 位清除寄存器控制。

位设置\清除寄存器BSRR,位清除寄存器BRR

BSRR位设置\清除寄存器

高16位清除为0,低16位设置为1.

Windows工控机怎么调用io python 工控机gpio怎么控制_嵌入式_03

BRR位清除寄存器

Windows工控机怎么调用io python 工控机gpio怎么控制_stm32_04

代码:

#include "stm32f10x.h"

int main(void)
{
	GPIOA->CRL = 0x33333333;//0x00000033前面的零是可以省略的
	GPIOA->CRH = 0x44444444;
	while(1)
	{
		if((GPIOA->IDR&0x0100) == 0x0100) 	GPIOA->BSRR |= 0x0001;
		else 																GPIOA->BRR |= 0x0001;
		
		if((GPIOA->IDR&0x0200) == 0x0200)		GPIOA->BSRR |= 0x0002;
		else 																GPIOA->BRR |= 0x0002;
		
		if((GPIOA->IDR&0x0400) == 0x0400)		GPIOA->BSRR |= 0x0004;
		else 																GPIOA->BRR |= 0x0004;
		
		if((GPIOA->IDR&0x0800) == 0x0800)		GPIOA->BSRR |= 0x0008;
		else 																GPIOA->BRR |= 0x0008;
	}
	return 0;
}

方式3 位绑定

位绑定的定义:

位段
CortexTM-M3存储器映像包括两个位段(bit-band)区。这两个位段区将别名存储器区中的每个字映射到位段存储器区的一个位,在别名存储区写入-一个字具有对位段区的目标位执行读-改-写操作的相同效果。
在STM32F10xxx里,外设寄存器和SRAM都被映射到-一个 位段区里,这允许执行单一的位段的写和读操作。
下面的映射公式给出了别名区中的每个字是如何对应位带区的相应位的:
bit_ word_addr= bit_ band_base + (byte_offset * 32) + (bit_number * 4)
其中:
bit_ word addr 是别名存储器区中字的地址,它映射到某个目标位。
bit
band_ base 是别名区的起始地址。
byte
offset是包含 目标位的字节在位段里的偏移地址。
bit_ number是目标位所在位置(0-31)

个人理解

绑定地址 = 位绑定基地址+目标位偏移量
(不过这里的位绑定基地址是芯片制造商定好的地址。)

bit_ band_base 位绑定基地址
SRAM 的位绑定基地址:0x2200 0000
片上外设的位绑定的基地址:0x4200 0000
byte_ offset目标位偏移量
GPIOA->ODR为例子:
GPIOA->ODR地址 
= GPIOA_BASE + 0x0C
= APB2PERIPH_BASE + 0x0800 + 0x0C 
= PERIPH_BASE+0x10000+0x0800+0x0C 

而 GPIOA->ODR 的目标位偏移量: byte_ offset =  PERIPH_BASE+0x10000+0x0800+0x0C  - PERIPH_BASE = 0x00010800C

以计算GPIOA->ODR 的 第n位绑定地址为例子:
bit_word_addr = 片上外设别名地址 + GPIOA->ODR相对GPIOA的偏移地址* 32 + n * 4
bit_word_addr = 0x42000000 + 0x00010800C*32 + n * 4

相关寄存器:

Windows工控机怎么调用io python 工控机gpio怎么控制_寄存器_05


学习截图:

Windows工控机怎么调用io python 工控机gpio怎么控制_寄存器_06

代码:

注意IDR绑定的位是第8位,不是第0位!!!

#include "stm32f10x.h"

int main(void)
{
	//配置GPIO
	GPIOA->CRL = 0x33333333;
	GPIOA->CRH = 0x44444444;
	
	//GPIOA->ODR地址 = (int*)(GPIOA_BASE+0x0C+0*4)
	//= (int*)((APB2PERIPH_BASE + 0x0800)+0x0C+0*4)
	//= (int*)(((PERIPH_BASE + 0x10000) + 0x0800)+0x0C+0*4)
	//= (int*)(((0x40000000 + 0x10000) + 0x0800)+0x0C+0*4)
	//= (int*)(0x4001080C)
	int *PAO0 = (int*)(0x42000000 + (0x4001080C - 0x40000000)*32 +0*4);
	
	//GPIOA->IDR地址 = GPIOA_BASE + 0x08
	//= (int*)((APB2PERIPH_BASE + 0x0800)+0x08+0*4)
	//= (int*)(((PERIPH_BASE + 0x10000) + 0x0800)+0x08+0*4)
	//= (int*)(((0x40000000 + 0x10000) + 0x0800)+0x08+0*4)
	//= (int*)(0x40010808)
	int *PAI0 = (int*)(0x42000000 + (0x40010808 - 0x40000000)*32 +8*4);
	while(1)
	{
		//位绑定
		if(*PAI0 == 1) 	*PAO0 = 1;
		else 						*PAO0 = 0;
		
		//下面与上面的位绑定作对比
		if((GPIOA->IDR&0x0200) == 0x0200)		GPIOA->BSRR |= 0x0002;
		else 																GPIOA->BRR |= 0x0002;
	}
	return 0;
}

公式代码:

(利用位的与运算保留 高位 或 低位)
(注意输入是高位,是8-15)

#include "stm32f10x.h"

#define GPIOA_ODR (GPIOA_BASE+0x0C)
#define GPIOA_IDR (GPIOA_BASE+0x08)

#define BitBand(Addr,bitNum) *((volatile unsigned long *)((Addr&0xf0000000)+0x2000000+((Addr&0xfffff)<<5)+(bitNum<<2)))
#define PAout(n) BitBand(GPIOA_ODR,n)
#define PAin(n)  BitBand(GPIOA_IDR,n)
int main(void)
{
	GPIOA->CRL = 0x33333333;//0x00000033前面的零是可以省略的
	GPIOA->CRH = 0x44444444;

	while(1)
	{
		//位绑定
		if(PAin(8) == 1) 	
			PAout(0) = 1;
		else 						
			PAout(0) = 0;
		
		if(PAin(9) == 1) 	
			PAout(1) = 1;
		else 						
			PAout(1) = 0;					
		
		if(PAin(10) == 1)	
			PAout(2) = 1;
		else 							
			PAout(2) = 0;
	}
	return 0;
}

各GPIO位绑定代码块(复制粘贴):

#define GPIOA_ODR (GPIOA_BASE+0x0C)
#define GPIOA_IDR (GPIOA_BASE+0x08)
#define GPIOB_ODR (GPIOB_BASE+0x0C)
#define GPIOB_IDR (GPIOB_BASE+0x08)
#define GPIOC_ODR (GPIOC_BASE+0x0C)
#define GPIOC_IDR (GPIOC_BASE+0x08)
#define GPIOD_ODR (GPIOD_BASE+0x0C)
#define GPIOD_IDR (GPIOD_BASE+0x08)
#define GPIOE_ODR (GPIOE_BASE+0x0C)
#define GPIOE_IDR (GPIOE_BASE+0x08)

#define BitBand(Addr,bitNum) *((volatile unsigned long *)((Addr&0xf0000000)+0x2000000+((Addr&0xfffff)<<5)+(bitNum<<2)))
	
#define PAout(n) BitBand(GPIOA_ODR,n)
#define PAin(n)  BitBand(GPIOA_IDR,n)
#define PBout(n) BitBand(GPIOB_ODR,n)
#define PBin(n)  BitBand(GPIOB_IDR,n)
#define PCout(n) BitBand(GPIOC_ODR,n)
#define PCin(n)  BitBand(GPIOC_IDR,n)

二、stm32库函数

stm32库函数是由st公司提供的API,开发者可以使用库函数来配置寄存器,使开发者摆脱最底层的寄存器操作。有着开发快速,易于阅读的优点。
它向下操作寄存器,向上提供操作配置寄存器的接口。
SMSIS(Contex MicroController Software Interface Standard)标准,ARM公司与其他外设厂家建立的标准。