在单片机开发中,一般使用C语言进行编程,C语言提供了一种结构化的编程方法,能有效地管理和控制硬件资源。函数是C语言中的一个基本构建块,它允许开发者将程序分解成更小、更易于管理的部分。
函数是一段执行特定任务的代码块,它可以接受输入(称为参数),并可以返回一个结果。函数的主要目的是提高代码的可重用性和模块性。
函数在使用前必须被声明。声明通常包括函数的返回类型、函数名和参数列表。这告诉编译器函数的存在,其具体实现可以在别处。
和变量类似,一般在源文件中对函数进行定义,在头文件中对需要对外提供的函数进行声明,如某函数不需要对外提供,但又需要在其他函数中提前使用,请在源文件头部对函数进行声明。
当需要执行函数中的代码时,会进行函数调用。调用函数时,需要按照声明时的参数列表提供相应的参数。
函数可以有参数,这些参数为函数提供了执行操作所需的数据。参数在函数调用时指定,并在函数执行期间使用。为了编译器的兼容性,如果函数没有参数,也最好将参数类型设为void。
函数可以有一个返回类型,指定了函数执行完成后返回给调用者的数据类型。如果函数不返回任何值,则其返回类型为void
。
在STM32等单片机开发中,函数的使用非常广泛,例如:
STM32提供了一套标准库,里面提供了单片机底层硬件的访问和控制,如GPIO、FLASH、IIC、USART等,如在stm32f10x_gpio中,GPIO_SetBits用于将某GPIO口的引脚电平拉高(置1,输出高电平),GPIO_ResetBits用于将某GPIO口的引脚电平拉低(置0,输出低电平)。
STM32提供了一套硬件抽象层库,这些库的函数简化了对底层硬件的访问和控制。例如,HAL_GPIO_TogglePin()
函数用于切换GPIO引脚的状态。
中断服务例程是特殊的函数,用于响应硬件中断。例如,当外部设备(如按钮)生成中断信号时,相应的ISR会被执行,以处理该中断。
开发者可以定义自己的函数来执行特定的任务,比如数据处理、通信协议的实现等。这些函数增加了代码的模块性和可读性。
在某些异步操作中,可以使用回调函数来处理完成后的事件。例如,在完成异步串行通信后,可以通过回调函数来处理接收到的数据。
通过函数,可以将常用的代码封装起来,以便在多个地方重用,减少代码冗余。
函数允许开发者将复杂的程序分解成更小的、易于管理的单元,每个单元执行特定的任务。
当程序逻辑需要更改或修复时,有了函数划分,开发者只需关注与问题相关的部分,而不必梳理整个程序代码。
返回类型 函数名(参数声明)
{
函数体;
}
返回类型:void、char、unsigned char、int、unsigned int、float、double、uint8_t、uint16_t、uint32_t等
函数名:由英文字母、数字、下划线组成。函数名的起始位只能为字母或下划线
参数声明:可以是多个参数或void
函数体:由多个语句或代码段组成。
#include "stm32f10x.h"
#include "stdbool.h"
#define LED_DEBUG_PORT GPIOA
#define LED_DEBUG_PIN GPIO_Pin_10
void LED_DebugSetOn(void)
{
GPIO_SetBits(LED_DEBUG_PORT , LED_DEBUG_PIN); // 打开
}
void LED_DebugSetOff(void)
{
GPIO_ResetBits(LED_DEBUG_PORT , LED_DEBUG_PIN); // 关闭
}
void LED_DebugSet(bool value)
{
if(value == false)
{
GPIO_ResetBits(LED_DEBUG_PORT , LED_DEBUG_PIN); // 关闭
}
else
{
GPIO_SetBits(LED_DEBUG_PORT, LED_DEBUG_PIN); // 点亮
}
}
2)自定义函数的使用
void DELAY_1us(void)
{
uint32_t ticks;
//MCU执行1us所走的时钟步数
ticks = (SystemCoreClock / 1000000);
//非精确延时等待
while (ticks--);
}
void DELAY_Nus(uint16_t nus)
{
while(nus--)
{
DELAY_1us();
}
}
void DELAY_1ms(void)
{
for (int i = 0;i < 1000; i++)
{
DELAY_1us();
}
}
void DELAY_Nms(uint16_t nms)
{
while(nms--)
{
DELAY_1ms();
}
}