C语言和单片机学习中零散的知识点
1.关于计算打印字符。
int a = 10;
int b =3;
int c = a / b;
printf("%03d,c") //这里输出的是003 如果是%02d,输出的是03 这里的%03d表示输出
printf("%3d\r\n", c); //如果前面没有两个03的话,会打印 3。前面是两个空格。
printf("20%06d",c); //输出20000003 前面加一个20表示加上了一个固定的字符串20
float d = a / b;
printf("%f", d) ; //3.000000 得到3.000000是因为a和b都是整数,所以会输出小数点后面没有数字
printf("20%f", d); //203.000000
printf("%02f", d); //模仿d的写法,结果仍然是3.000000 不会修改个数的。
float d = 10.0;
int e = 3;
float f = d / e;
printf("%f", f); //3.33333305.1
printf("%05.1f\r\n", f); //打印003.3 这里的意思是一共有5位数,不够的前面补零。.1表示后面跟着1位小数
printf("%5.1f\r\n", f); //打印 3.3 这里相当于把0替换成了空格。
printf("%05.2f\r\n", f); //打印03.33
2.\r\n
\r:将当前位置移到本行的开头,又叫回车。
\n:将当前位置移到下一行开头,又叫换行。
不加\r\n
都加上\r\n
只加\n
只加\r
3.如下图所示,在C语言中,定时String类型的数据会报错
C语言中定义不了String,报错未定义的标识符String。
这个S大写和小写都不行
加上了头文件<String.h>也不行
用C++试一下
后来查资料可知,C语言中是没有定义没有定义字符串类型的。
如果想要表示字符串类型的,C语言中是靠char[20] 数组来实现的。
4.UART和USART的区别
UART是通用异步收/发器
USART是通用同步/异步收/发器
在异步通信中,发送方和接收方之间没有公共时钟。它广泛用于面向字节的传输,这意味着它一次可以发送 1 个字节或字符。与同步相比,异步通信速度较慢,并且还具有启动和停止位的开销。在异步通信中,每一帧都用开始和停止位进行包装。让我们看看异步通信的帧结构。
在同步通信中,时钟由发送方和接收方共享。我们可以在其中传输一个数据块,并且对于该数据块只有一个开始和停止位。这是同步通信开销较小的原因。
总的来说就是异步通信通信的双方没有相同的时钟线控制,波特率等一些参数需要自己设置,同步通信有一根时钟线控制。
int sprintf(char* buffer,const char *format[,argument]……); 格式化字符串
把format里面的东西复制到buffer里面,
第5.一个参数是转换后要存的地方,第二个参数是格式化字符串,比如%d,%f,%c,
注意:这里要用sprintf_s 而不是sprintf 不然会报错。
5.在使用LVGL的时候,如果屏幕出现白屏,可以将启动文件中的Stack_Size EQU 0x00000400
改成0x0000080
如果出现内存不足的情况,可以将点击Options–>Target中Rom和Ram的值修改了。或者将malloc文件下的MEM1_MAX_SIZE改小一点。
6.C语言中char和char数组输出字符串
这里可以看到,char类型给的数组长度是20,后面空格自动省略了,因为我后面直接输出字符a时是紧跟在char数组输出内容的后面。
- char str[7];
- str = "abc123"; //错误
- //正确
- str[0] = 'a'; str[1] = 'b'; str[2] = 'c';
- str[3] = '1'; str[4] = '2'; str[5] = '3';
这里要注意有一个坑,字符数组只有在定义时才能将整个字符串一次性的赋值给它,一旦定义完了,就只能一个字符一个字符的赋值了。
要注意的是,在每次给字符数组赋值的时候,要在结尾加上'\0'.
如果不加\0
加上\0之后
如果是直接定义则不需要加\0,加和不加结构都是一样的。
可以用string.h文件中的strlen函数求数组的长度
注意\0是不被计算到总长度里面的。
从下图可以看到,如果字符型的单个赋值的话,如果尾部不加'\0',不仅打印的数据会出错,通过strlen计算得到的长度也会报错。
7.C语言中的结构体
结构体struct 后面的Student是标签,在main函数中使用的时候 要先Student student2,然后
student.name 这样才可以赋值.
而结构体后面跟着的studnet1,在main函数里可以直接student.name的方式赋值。
如果前面跟了typedef关键字,那么student1就等同于Student了。在面函数需要先定义才可以。
此外,还可以在结构体这里直接赋值
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} book = {"C 语言", "RUNOOB", "编程语言", 123456};
用(.)的方式可以访问结构体成员。
结构体也可以作为函数的参数。
结构体指针
使用结构体指针不能直接赋值,如下图所示,这样的方式是错误的。
#include <stdio.h>
struct Student
{
int age;
int num;
};
int main()
{
Student abc;
Student *student;
student->age = 10;
printf("%d", student->age);
return 0;
}
结构体指针不能写成和普通结构体那样的同样的赋值的方法,二者不是一样的。
结构体指针应该这样赋值,结构体指针用 -> 取值。
#include <stdio.h>
struct Student
{
int age;
int num;
};
int main()
{
Student abc;
struct Student* student = &abc;
student->age = 10;
printf("%d", student->age);
return 0;
}
从上图可知,如果用tpedef定义一个结构体的话,后面,必须要加struct,struct后面可加可不加,具体看情况,如果typedef enum 是这种情况的话,在mian函数下面直接定义给值就可以了。
8.C语言之指针
#include <stdio.h>
int main()
{
int a = 5;
printf("a = %d\r\n", a);
printf("&a = %d\r\n", &a);
int* p;
p = &a;
printf("p = %d\r\n", p);
printf("*p = %d\r\n", *p);
printf("&p = %d\r\n", &p);
int** q;
q = &p;
printf("q = %d\r\n", q);
printf("*q = %d\r\n", *q);
printf("&q = %d\r\n", &q);
int** m;
m = q;
m = &q; //报错
m = &a; //报错
return 0;
}
9.C语言中一些函数的使用
memcpy
C 库函数 void *memcpy(void *str1, const void *str2, size_t n) 从存储区 str2 复制 n 个字节到存储区 str1。
下面是 memcpy() 函数的声明。
void *memcpy(void *str1, const void *str2, size_t n)
参数
返回值
该函数返回一个指向目标存储区 str1 的指针。
// 将字符串复制到数组 dest 中
#include <stdio.h>
#include <string.h>
int main()
{
const char src[50] = "http://www.runoob.com";
char dest[50];
//printf("%d\r\n",strlen(src));
memcpy(dest, src, strlen(src)+1);
printf("dest = %s\n", dest);
return(0);
}
结果
Strlen 计算字符串长度
这里 memcpy(dest, src, strlen(src)+1) 要进行加1的操作。也就是算上\0.
如果不加,最后的结果为
memset 和 memcpy
二者的区别是
memset是将第二个参数的值赋给第一个参数,第二个参数是一个数值类型的数。像什么unisgned char,unsigned int ,int ,long 等等。第一个参数是数组类型的数。
memcpy的第一个和第二个参数都是数组类型的。
他们的第三个参数是一样的。都是表示传输的字节数,所以这里土建使用unsigned char 类型的。
#include <stdio.h>
#include <string.h>
int main()
{
unsigned char arr[6] = "abcde";
unsigned char arr1[6];
memcpy(arr1, arr, 6);
printf("%s\r\n", &arr1[2]);
printf("%s\r\n", arr1);
printf("%s\r\n", &arr);
}
可以看到%s可以打印数组当前以及当前之后的内容。
10.为什么单片机主频的时钟频率优先选择HSE而不是HSI?
疑问:1.stm32f103c8t6是如何选择为外部时钟的
2.选择好之后如何通过PLL配置时钟
我这里只看到 在stm32f10x.h文件下 第115行
#if !defined HSE_VALUE
#ifdef STM32F10X_CL
#define HSE_VALUE ((uint32_t)25000 000)
#else
#define HSE_VALUE ((uint32_t)8000 000)
#endif
#endif
这里的意思只是说如果STM32单片机的型号是STM32F10X_CL的话,配置主频为25Mhz的时钟频率,如果不是这个型号的话,就配置为8Mhz的频率。但具体的细节比如说用PLL配置成这样的。
如何让NRST引脚输出低电平复位?(猜想)
1.输入电压小于1V(正常是3.3V)
2.外加一个低电平试一下
单片机如何实现软件复位?
作者:1个程序源