STM32入门学习——每天进步一点点(记得多写代码多总结((一))

c文件及h文件中所有代码、全局变量、局部变量、’const’限定符定义的常量数据、startup.asm文件中的代码(类似ARM中的bootloader或者X86中的BIOS,一些低端的单片机是没有这个的)通通都存储在ROM中。

RAM——程序运行中数据的随机存取(掉电后数据消失)
整个程序中,所用到的需要被改写的量,都存储在RAM中,“被改变的量”包括全局变量、局部变量、堆栈段。

FLASH——存储用户程序和需要永久保存的数据。

ROM的大小疑问:

对于flash类型的MCU,ROM空间的大小通常都是整字节的,即为ak8bits。这很好理解,一眼就知道,ROM的空间为aK。但是,对于某些OTP类型的单片机,比如holtek或者sonix公司的单片机,经常看到数据手册上写的是“OTP progarming ROM 2k15bit…”,可能会产生疑惑,这个“15bit”认为是1个字节有余,2个字节又不足,那这个ROM空间究竟是2k,多于2k,还是4k但是少了一点点呢br> 答:这里要明确两个概念:一个是指令的位宽,另一个是指令的长度。指令的位宽是指一条指令所占的数据位的宽度;有些是8位位宽,有些是15位位宽。指令长度是指每条指令所占的存储空间,有1个字节,有2个字节的,也有3个字节甚至4个字节的指令。实事上也确实如此,当在反汇编或者汇编时,可以看到,复合指令的确是有简单的指令组合起来的。

三、flash
关于flash,在单片机中需要外接,且需要cup具有SPI接口
例如:25PE80V6、25080BVSIG等

移位运算符
移动操作符可以把数字中每个二进制数位统一想左或者向右移动n个位置,移动操作会得到一个新数字,不会修改原来的数字。

1)

向左移动是右边空出来的位置上一定补充0
例如 二进制 (0000 0011) 3 0000 0011 3 x 2^2 =12
0000 1100

再如:

-5

对于unsigned类型,右移时使用0填充左端空出的位。对于有符 类型,结果依赖于机器。空出的位可能用0填充,或者使用符 (最左端的)位的副本填充。

例如 二进制 (0000 1100) >> 2 向右移动两位结果为 0000 0011

12 0000 1100 12 / 2^2 = 3

也可以这么理解,相对于unsigned类型而言,向右移动n位相当于除以2的n次方

注意:

应避免使用 a

所以说,左移和右移的位数不能大于数据的长度,不能小于 0。
位运算的用法
五、位运算符用法

1、掩码

flags &= MASK;

例如:flags二进制为 1001 0110 MASK二进制为 0000 0010 即:

flags &= 0x02;

flags = 0000 0010

这个语句将导致flags的除位 1之外,所有位都被设为 0。

2、打开位

flags |= MASK;

例如:flags二进制为 1001 0100 MASK二进制为 0000 0010 即:

flags |= 0x02;

flags = 1001 0110

这个语句将flags中的位1设为1,并保留其他所有位不变。

结合移位运算符

flags |= MASK

例如:flags二进制为 1001 0110 MASK二进制为 0000 0001 n为4即:

flags |= 0x01

flags = 1001 1110

这个语句将flags的位 3 设为1,并保留其他所有位不变。

3、关闭位

flags &= ~MASK;

例如:flags二进制为 1001 0110 MASK二进制为 0000 0010 即:

flags &= ~0x02;

flags = 1001 0100

这个语句将flags除位1设为0以外,保留其他所有位不变。

结合移位运算符

flags &= ~(MASK

例如:flags二进制为 1001 0110 MASK二进制为 0000 0001 n为3即:

flags &= ~(0x01

flags = 1001 0010

这个语句将flags的位 2 设为0,并保留其他所有位不变

4、转置位

flags ^= MASK;

例如:flags二进制为 1001 0110 MASK二进制为 0000 0010 即:

flags ^= 0x02;

flags = 1001 0100

转置一个位表示如果该位打开,则关闭该位,如果该位关闭,则打开该位。

5、查看一位的值

if ((flags & MASK) == MASK)

puts (“Wow);

例如:flags二进制为 1001 0110 MASK二进制为 0000 0010 即:

if ((flags & 0x02) == 0x02)

puts (“Wow);

所有基础的数据类型, 最大的也不过 10 个字节;

int main()
{
struct Bit
{
unsigned a: 1; /* 1 Bit, 取值范围: 0 – 1 /
unsigned b: 2; /
2 Bit, 取值范围: 0 – 3 /
unsigned c: 3; /
3 Bit, 取值范围: 0 – 7 /
unsigned d: 4; /
4 Bit, 取值范围: 0 – 15 */
}B;
B.a = 1;
B.b = 3;
B.c = 7;
B.d = 15;
printf(“%d, %d, %d, %d/n”, B.a, B.b, B.c, B.d);
getchar();
return 0;
}

上例中, 位域的类型被指定为是无符 的整型(unsigned int), 我试着只要是整型都可以, 但要一致。

struct Bit {
int b8: 1;
int b7: 1;
int b6: 1;
int b5: 1;
int b4: 1;
int b3: 1;
int b2: 1;
int b1: 1;
} B;
unsigned char *p = NULL;

B.b1 = 1; B.b2 = 1; B.b3 = 1; B.b4 = 1; B.b5 = 1; B.b6 = 1; B.b7 = 1; B.b8 = 1;
p = (unsigned char *)&B;
printf(“%dn”, p); / 255 */

B.b1 = 0; B.b2 = 0; B.b3 = 0; B.b4 = 0; B.b5 = 0; B.b6 = 0; B.b7 = 0; B.b8 = 1;
p = (unsigned char *)&B;
printf(“%dn”, p); / 1 */

B.b1 = 0; B.b2 = 0; B.b3 = 0; B.b4 = 0; B.b5 = 1; B.b6 = 1; B.b7 = 1; B.b8 = 1;
p = (unsigned char *)&B;
printf(“%dn”, p); / 15 */

B.b1 = 0; B.b2 = 1; B.b3 = 1; B.b4 = 1; B.b5 = 1; B.b6 = 1; B.b7 = 1; B.b8 = 1;
p = (unsigned char *)&B;
printf(“%dn”, p); / 127 */

getchar();
return 0;

包含位字段的结构和其他结构没有区别, 譬如同时包含其他类型的字段:

#include

int main(void)
{
struct Bit {
unsigned b1: 1;
unsigned b2: 1;
float f;
} B;
B.b1 = 0;
B.b2 = 1;
B.f = 3.14;
printf(“%d, %d, %gn”, B.b1, B.b2, B.f);

getchar();
return 0;
}

  1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:
    struct bs
    {
    unsigned a:4
    unsigned :0 /空域/
    unsigned b:4 /从下一单元开始存放/
    unsigned c:4
    }
    在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。
  2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。
  3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:
    struct k
    {
    int a:1
    int :2 /该2位不能使用/
    int b:3
    int c:2
    };
    从以上分析可以看出,位域在本质上就是一种结构类型, 不过其成员是按二进位分配的。

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2019年7月22日
下一篇 2019年7月22日

相关推荐