草庐IT

01、【江科大自化协stm32F103c8t6】笔记之【入门32单片机及GPIO初始化参数配置】

Clockwisee 2023-08-30 原文

目录

一、前言

前几天系统地将32单片机学习了一下,学习的视频是bilibili的江科大自化协c8t6的教学,为了方便以后使用,在这里和b站视频联动写下一篇笔记,以便自己查阅资料和调用函数。

二、必要资料

1、C语言类型

  • int在51单片机中是16位的,在STM32中32位的,如果要用16位的数据要用short来表示
  • float和double都是带符号的,没有不带符号的
  • 枚举enum的使用,类似于struct结构体,只是赋值且引用是有范围限制的


2、片上资源/外设

3、引脚定义

  • 不要轻易使用PA15,PB3,PB4,他们是作为调试端口的

4、系统结构


性能:AHB>APB2>APB1(注意关注这三者里面的外设,其实后两者性能差不多)

三、GPIO初始化

1、首先使用RCC开启GPIO的时钟

从APB2总线,引出RCC_APB2PeriphClockCmd(GPIO口的名字,状态),如使GPIOA 使能:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 

2、其次使用GPIO_Init函数初始化GPIO

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)

第一个参数 GPIO_TypeDef* GPIOx 通过x选定GPIO, 如:GPIOA
第二个参数 GPIO_InitTypeDef* GPIO_InitStruct是GPIO的结构体地址 如:&GPIO_InitStructure

  • struct 关键字,定义结构体变量
    用途:数据打包,不同类型的变量打包(可以数组,数组是同一个类型打包)

  • #define 新名字 旧名字(无脑式定义)
    typedef 旧名字 新名字(定义 长变量类型名);
    因为结构体变量类型较长,所以通常用typedef更改变量类型名

    比如:

    将结构体变量 struct{…} 换一个别名叫GPIO_InitTypeDef

我们把GPIO_InitTypeDef取个名字叫GPIO_InitStructure放到void GPIO_Init()上面并且在void GPIO_Init()中取地址&GPIO_InitStructure

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 
GPIO_InitTypeDef GPIO_InitStructure

void GPIO_Init(GPIOA,GPIO_InitTypeDef* GPIO_InitStruct)

由上面struct{…}结构体知道GPIO_InitStructure 有三个参数分别用.引出:
(也可以用->直接指向结构体成员即可,就不必用*取地址和.引出结构体)

GPIO_InitStructure.GPIO_Mode
GPIO_InitStructure.GPIO_Pin
GPIO_InitStructure.GPIO_Speed

第一个Mode有8种模式

GPIO_Mode_AIN(Analog IN)//模拟输入 
GPIO_Mode_IN_FLOATING  //浮空输入
GPIO_Mode_IPD (In Pull Down) //下拉输入
GPIO_Mode_IPU (In Pull Up) //上拉输入
GPIO_Mode_OUT_OD(Out Open Drain) //开漏输出
GPIO_Mode_PP_OD(Out Push Pull) //推挽输出
GPIO_Mode_AF_OD(Atl Open Drain) //复用开漏
GPIO_Mode_AF_PP(Atl Push Pull) //复用推挽

  • 开漏 高电平没有驱动能力
  • 推挽 高低电平都有驱动能力

第二个GPIO_InitStructure.GPIO_Pin 的选择

第三个GPIO_InitStructure.GPIO_Speed的选择

我们一般选50MHz

最后结果如下:

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

这样我们就把GPIOA 上所有引脚都初始化好了。

3、最后使用输入或输出的函数控制GPIO口

————————————————————————————————————————————————end
这里总共涉及了RCC和GPIO两个外设

★常用的三个RCC外设

void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);

★读写GPIO的8个函数

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);

例1:
GPIO_SetBits :  拉高引脚输出电平 //1
GPIO_ResetBits :拉低引脚输出电平 //0

		GPIO_ResetBits(GPIOA, GPIO_Pin_0); //将PA0口置0
		Delay_ms(500);
		GPIO_SetBits(GPIOA, GPIO_Pin_0);//将PA0口置1
		Delay_ms(500);
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);//Bit_RESET设置低电平
		Delay_ms(500);
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
		Delay_ms(500);
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0);//强制转换BitAction类型 0 1
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1);
		Delay_ms(500);

例2:读取GPIO上 电平操作

GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);//读取PB13上引脚输入 一般是接一个按键 读它的输入 即是否按下
GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1)//读取PA1上引脚输出 一般接光敏传感器 读它的AO口输出  即是否被遮挡

例3:灯的函数使用

//灯的打开
void LED1_ON(void)
{
	GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
//灯的熄灭
void LED1_OFF(void)
{
	GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
//灯的翻转
void LED1_Turn(void)
{
	if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0)
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_1);
	}
	else
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_1);
	}
}

四、delay,oled函数的调用

1、delay

Delay_us();
Delay_ms();
Delay_s();

Delay.h

#ifndef __DELAY_H
#define __DELAY_H

void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
void Delay_s(uint32_t s);

#endif

2、oled


上述代码添加.c和.h文件后可以直接调用

有关01、【江科大自化协stm32F103c8t6】笔记之【入门32单片机及GPIO初始化参数配置】的更多相关文章

  1. ruby-on-rails - 未初始化的常量 Psych::Syck (NameError) - 2

    在我的gem中,我需要yaml并且在我的本地计算机上运行良好。但是在将我的gem推送到ruby​​gems.org之后,当我尝试使用我的gem时,我收到一条错误消息=>"uninitializedconstantPsych::Syck(NameError)"谁能帮我解决这个问题?附言RubyVersion=>ruby1.9.2,GemVersion=>1.6.2,Bundlerversion=>1.0.15 最佳答案 经过几个小时的研究,我发现=>“YAML使用未维护的Syck库,而Psych使用现代的LibYAML”因此,为了解决

  2. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  3. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  4. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  5. ruby-on-rails - 独立 ruby​​ 脚本的配置文件 - 2

    我有一个在Linux服务器上运行的ruby​​脚本。它不使用rails或任何东西。它基本上是一个命令行ruby​​脚本,可以像这样传递参数:./ruby_script.rbarg1arg2如何将参数抽象到配置文件(例如yaml文件或其他文件)中?您能否举例说明如何做到这一点?提前谢谢你。 最佳答案 首先,您可以运行一个写入YAML配置文件的独立脚本:require"yaml"File.write("path_to_yaml_file",[arg1,arg2].to_yaml)然后,在您的应用中阅读它:require"yaml"arg

  6. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  7. ruby-on-rails - 未在 Ruby 中初始化的对象 - 2

    我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调

  8. ruby-on-rails - 在默认方法参数中使用 .reverse_merge 或 .merge - 2

    两者都可以defsetup(options={})options.reverse_merge:size=>25,:velocity=>10end和defsetup(options={}){:size=>25,:velocity=>10}.merge(options)end在方法的参数中分配默认值。问题是:哪个更好?您更愿意使用哪一个?在性能、代码可读性或其他方面有什么不同吗?编辑:我无意中添加了bang(!)...并不是要询问nobang方法与bang方法之间的区别 最佳答案 我倾向于使用reverse_merge方法:option

  9. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  10. ruby - 定义方法参数的条件 - 2

    我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano

随机推荐