单片机(STM32)开发中常用的C语言基础语法(一)
1、sprintf函数
sprintf 是一个在 C 语言中常用的函数,用于将格式化的数据写入字符串中。它的函数原型如下:
sprintf函数会将传递给它的可变参数按照指定的格式进行格式化,并将结果写入str` 指向的字符串中。返回值是写入字符串的字符数(不包括字符串末尾的空字符)。
sprintf 函数在 C 语言中是标准库函数,它定义在 stdio.h 头文件中。
❝[!TIP] 注:在sprintf函数中打印百分号(%),您需要使用两个百分号(%%)。这是因为在sprintf函数中,百分号被用作转义字符,表示要插入格式化输出。
#include <stdio.h>
int main() {
char buffer[100];
int a = 10;
float b = 3.14;
char c = 'd';
sprintf(buffer, "整数:%d, 浮点数:%f, 字符:%c", a, b, c);
printf("%s\n", buffer);
return 0;
}
输出结果
整数:10, 浮点数:3.140000, 字符:d
sprintf所写入的字符串为char类型。而一些屏幕驱动显示函数所需的参量类型为uint8_t
。建议强制类型转换以避免warning。一般情况下实测该warning不影响程序运行。
LCD_DisplayStringLine(u8 Line, u8 *ptr)
一种规范的写法:
char text[30];
unsigned int i=5;
sprintf(text,"CNDR:%d%% ",i);
LCD_DisplayStringLine(Line9,(unsigned char*)text);
2、bool布尔类型
在C语言中,布尔类型是一种基本的数据类型,用于表示逻辑值true
和false
。 在C99标准及其之后的标准中,C语言在<stdbool.h>头文件中提供了内置的布尔类型支持。当你包含这个头文件时,你可以使用bool
关键字来声明布尔变量,使用true和false来表示布尔值。例如:
#include <stdbool.h>
bool a = true;
bool b = false;
请注意,true
和false
在C99中是关键字,它们的值分别是1和0。同时,bool实际上是一个宏,通常被定义为_Bool或者int。
3、结构体struct与typedef struct
struct和typedef struct都是用来定义结构体的关键字
struct Student {
int id;
char name[50];
int age;
};
struct Student stu1;
stu1.id = 1;
stu1.name = "John Doe";
stu1.age = 20;
在这个例子中,我们定义了一个名为Student
的结构体,它包含三个成员:id
,name
,和age
。其中,id
是一个整数,name
是一个字符数组(可以存储一个长度为50的字符串),age
也是一个整数,创建了一个名为stu1
的Student
结构体实例,并为其成员赋值。
在C语言中,使用typedef
和struct
来定义结构体类型的语法如下:
typedef struct {
// 成员变量定义
// ...
} 结构体别名;
typedef struct StructName {
// 成员变量定义
// ...
} StructName;
/*下面举一个例子*/
#include <stdio.h>
typedef struct {
char name[50];
int age;
} Person;
int main() {
Person p1; // 使用别名声明结构体实例
p1.age = 25;
printf("Name: %s\n", p1.name);
printf("Age: %d\n", p1.age);
return 0;
}
在上述示例中,我们定义了一个名为Person
的结构体类型,并使用别名Person
来声明结构体实例p1
。然后,我们可以使用点号.
来访问结构体成员变量,例如p1.name
和p1.age
。
结构体指针成员变量引用方法是通过“->”符号实现,比如要访问 usart3 结构体指针指向的结 构体的成员变量 BaudRate,方法是:Usart3->BaudRate;
4、弱定义extern,__weak
在C语言中,弱定义是一种允许同一个符号(变量或函数)在多个源文件中被定义,但在链接时只有一个定义会被保留的定义方式。弱定义使用extern
关键字来声明变量或函数,并且在声明后面不跟任何分号。
下面是一个使用弱定义的示例:
假设我们有一个全局变量global_var
,需要在多个源文件中共享。我们可以将其声明为弱变量,并在其中一个源文件中定义它:
// 在头文件中声明弱变量
extern int global_var;
// 在源文件1.c中定义弱变量
int global_var = 10;
在其他源文件中,我们可以使用extern
关键字来引用global_var
变量,例如:
// 在源文件2.c中引用弱变量
extern int global_var;
void func() {
printf("The value of global_var is %d\n", global_var);
}
在链接时,链接器会选择其中一个定义作为最终的定义,其他定义将被忽略。因此,在最终的可执行程序中,只有一个global_var
变量会被定义,并且可以被所有源文件访问。
需要注意的是,弱定义只能用于变量或函数,不能用于函数参数、结构体、枚举等其他类型。此外,弱定义必须保证只有一个强定义(使用static
关键字定义的变量或函数),否则会导致链接错误。
❝[!CAUTION] 需要注意的是:
extern int global_var=10;
此类写法是不允许的。
__weak
关键字用于修饰函数或变量,表示该函数或变量是弱定义的。
大部分中断回调函数都被__weak
关键字修饰
具体来说,当你在代码中声明一个弱定义的函数或变量时,如果你没有在其它地方定义这个函数或变量,编译器会报错。
而使用__weak
关键字可以告诉编译器,这个函数或变量是弱定义的,如果在其它地方没有定义,则使用这个弱定义的函数或变量。
__weak
关键字通常用于在不同的模块之间共享函数或变量,特别是在嵌入式系统中,不同的模块可能会使用相同的函数或变量名,为了避免冲突,使用弱定义是一种有效的解决方法。
需要注意的是,__weak
关键字并不是C语言的标准化关键字,而是特定编译器或环境提供的扩展。
5、__IO定义
__IO
是一个在嵌入式C语言中常见的关键字,特别是在与硬件相关的编程中。__IO
通常用于指定一个变量或地址空间为输入输出(IO)空间。
在大多数处理器架构中,内存被划分为几个不同的空间,例如:RAM、ROM、IO空间等。__IO
关键字用于告诉编译器,某个变量或指针引用的地址位于IO空间,而不是常规的RAM或ROM空间。
例如,当您在与硬件寄存器交互时,这些寄存器通常位于特殊的IO地址空间。在这种情况下,您可能会使用__IO
关键字来定义一个指向这些寄存器的指针:
__IO uint32_t* register_address = (uint32_t*)0x40000000;
在这个例子中,register_address
是一个指向地址0x40000000
的指针,并且这个地址被指定为IO空间。这样编译器就知道,当访问这个指针时,需要生成适用于访问IO空间的机器代码。
__IO
并不是C语言的标准关键字,而是特定于某些编译器和架构的扩展。
6、 ifdef 条件编译
在C语言中,#ifdef
是一个预处理指令,它用于进行条件编译。#ifdef
后面跟着一个宏名称,如果这个宏被定义了,那么#ifdef
后面的代码就会被编译进去,否则这部分代码会被忽略。
下面是一个简单的例子:
#include <stdio.h>
#define FEATURE_A
int main() {
#ifdef FEATURE_A
printf("Feature A is enabled.\n");
#else
printf("Feature A is not enabled.\n");
#endif
return 0;
}
在这个例子中,如果宏FEATURE_A
被定义了,那么程序会输出"Feature A is enabled."。如果宏FEATURE_A
没有被定义,那么程序会输出"Feature A is not enabled."。
在实际开发中,我们通常会使用#ifdef
来检查某些编译选项或者平台特性是否被定义,然后根据这些条件来选择性地编译代码。
7、printf串口重定向
这段 printf 函数支持的代码在初始化串口后使用,这段代码加入之后便可以通 过 printf 函数向串口发送我们需要的内容。
代码以STM32的HAL库版本作为示例:
//加入以下代码,支持 printf 函数,而不需要选择 use MicroLIB 标准库版本
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
_sys _exit(int x)
{
x = x;
}
//重定义 fputc 函数
int fputc(int ch, FILE *f)
{
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
USART_SendData(USART1,(uint8_t)ch);
return ch;
}
#endif
//HAL库版本
#include <stdio.h>//添加头文件
int fputc(int ch, FILE *f)//在串口文件中添加这段
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
8、switch case多路分支语法
switch语句是一种多路选择结构,可以根据不同的条件选择不同的执行路径。
switch (expression) {
case constant1:
// 代码块1
break;
case constant2:
// 代码块2
break;
...
default:
// 默认代码块
}
这是最简单和最常用的switch
语句结构。这里,expression
是要评估的表达式,constant1
、constant2
等是可能的值。如果expression
的值等于某个case
后面的常量,则执行相应的代码块。break
语句用于退出switch
语句。如果没有break
,程序将继续执行下一个case
。
原文地址:https://blog.csdn.net/2408_88910159/article/details/144024458
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!