文档库 最新最全的文档下载
当前位置:文档库 › STM32学习笔记-SYS程序解释(原子)

STM32学习笔记-SYS程序解释(原子)

STM32学习笔记-SYS程序解释(原子)
STM32学习笔记-SYS程序解释(原子)

SYS.C程序解释

#include

#include "sys.h"

//设置向量表偏移地址

//NVIC_VectTab:基址

//Offset:偏移量

//CHECK OK

//091207

void MY_NVIC_SetVectorTable(u32 NVIC_VectTab, u32 Offset)

{

//检查参数合法性

assert_param(IS_NVIC_VECTTAB(NVIC_VectTab));

assert_param(IS_NVIC_OFFSET(Offset));

SCB->VTOR = NVIC_VectTab|(Offset & (u32)0x1FFFFF80);//设置NVIC的向量表偏移寄存器

//用于标识向量表是在CODE区还是在RAM区

}

解释:前面两行是用来检查参数合法性,这里不作分析。重点看第三行。

#define NVIC_VectTab_RAM ((u32)0x20000000)

#define NVIC_VectTab_FLASH ((u32)0x08000000)

typedef struct

{

vuc32 CPUID;

vu32 ICSR;

vu32 VTOR;

vu32 AIRCR;

vu32 SCR;

vu32 CCR;

vu32 SHPR[3];

vu32 SHCSR;

vu32 CFSR;

vu32 HFSR;

vu32 DFSR;

vu32 MMFAR;

vu32 BFAR;

vu32 AFSR;

} SCB_TypeDef;

在<<权威指南>>第一百零四页,有这么一段话:

NVIC 中有一个寄存器,称为“向量表偏移量寄存器”(在地址0xE000_ED08处),通过修改它的值就能定位向量表。但必须注意的是:向量表的起始地址是有要求的:必须先求出系统中共有多少个向量,再把这个数字向上增大到是2的整次幂,而起始地址必须对齐到后者的边界上。例如,如果一共有32个中断,则共有32+16(系统异常)=48个向量,向上增大到2的整次幂后值为64,因此地址

地址必须能被64*4=256整除,从而合法的起始地址可以是:0x0, 0x100, 0x200等。Offset:是偏移量的计算

也就是说STM32自己有60个中断,加上CM3的16个,总共有76个中断,扩大到2的整次幂,那就是128,然后再乘以4,得到512,也就是0X200.根据这样计算,合法的偏移地址应该是0X0,0X200,0X400,0X600,0x800......

29 TBLBASE R/W 0 Table base in Code (0) or RAM (1)

28:7 TBLOFF R/W 0 Table offset value from Code region or RAM region

屏蔽前七位0x1FFFFF80和后三位+Offset + VECTTOR就是开始地址,低7位没有用到,所以&0X80。

VTOR设置只有BIT【28:7】,你把(u32)0x1FFFFF80二进制看看是不是【28:7】。

//设置NVIC分组

//NVIC_Group:NVIC分组0~4 总共5组

//CHECK OK

//091209

void MY_NVIC_PriorityGroupConfig(u8 NVIC_Group)

{

u32 temp,temp1;

temp1=(~NVIC_Group)&0x07;//取后三位

temp1<<=8;

temp=SCB->AIRCR; //读取先前的设置

temp&=0X0000F8FF; //清空先前分组

temp|=0X05FA0000; //写入钥匙

temp|=temp1;

SCB->AIRCR=temp;//设置分组

}

解释:CM3 内核支持256 个中断,其中包含了16 个内核中断和240 个外部中断,并且具有256级的可编程中断设置。但STM32 并没有使用CM3 内核的全部东西,而是只用了它的一部分。STM32 有76 个中断,包括16 个内核中断和60 个可屏蔽中断,具有16 级可编程的中断优先级。而我们常用的就是这60 个可屏蔽中断,所以我们就只针对这60 个可屏蔽中断进行介绍。

在 MDK 内,与NVIC 相关的寄存器,MDK 为其定义了如下的结构体:

typedef struct

{

vu32 ISER[2];

u32 RESERVED0[30];

vu32 ICER[2];

u32 RSERVED1[30];

vu32 ISPR[2];

u32 RESERVED2[30];

vu32 ICPR[2];

u32 RESERVED3[30];

vu32 IABR[2];

u32 RESERVED4[62];

vu32 IPR[15];

} NVIC_TypeDef;

STM32 的中断在这些寄存器的控制下有序的执行的。了解这些中断寄存器,你才能方便的

使用STM32 的中断。下面重点介绍这几个寄存器:

ISER[2]:ISER 全称是:Interrupt Set-Enable Registers,这是一个中断使能寄存器组。上面说了STM32 的可屏蔽中断只有60 个,这里用了2 个32 位的寄存器,总共可以表示64 个中断。而STM32 只用了其中的前60 位。ISER[0]的

bit0~bit31 分别对应中断0~31。ISER[1]的bit0~27对应中断32~59;这样总共60 个中断就分别对应上了。你要使能某个中断,必须设置相应的ISER位为1,使该中断被使能(这里仅仅是使能,还要配合中断分组、屏蔽、IO 口映射等设置才算是一个完整的中断设置)。具体每一位对应哪个中断,请参考stm32f10x_nvic..h 里面的第36 行处。

ICER[2]:全称是:Interrupt Clear-Enable Registers,是一个中断除能寄存器组。该寄存器组与ISER 的作用恰好相反,是用来清除某个中断的使能的。其对应位的功能,也和ICER 一样。这里要专门设置一个ICER 来清除中断位,而不是向ISER 写0 来清除,是因为NVIC 的这些寄存器都是写1 有效的,写0 是无效的。具体为什么这么设计,请看《CM3 权威指南》第125 页,NVIC 概览一章。

ISPR[2]:全称是:Interrupt Set-Pending Registers,是一个中断挂起控制寄存器组。每个位对应的中断和ISER 是一样的。通过置1,可以将正在进行的中断挂起,而执行同级或更高级别的中断。写0 是无效的。

ICPR[2]:全称是:Interrupt Clear-Pending Registers,是一个中断解挂控制寄存器组。其作用与ISPR 相反,对应位也和ISER 是一样的。通过设置1,可以将挂起的中断接挂。写0 无效。

IABR[2]:全称是:Active Bit Registers,是一个中断激活标志位寄存器组。对应位所代表的中断和ISER 一样,如果为1,则表示该位所对应的中断正在被执行。这是一个只读寄存器,通过它可以知道当前在执行的中断是哪一个。在中断执行完了由硬件自动清零。

IPR[15]:全称是:Interrupt Priority Registers,是一个中断优先级控制的寄存器组。这个寄存器组相当重要!STM32 的中断分组与这个寄存器组密切相关。IPR 寄存器组由15 个32bit 的寄存器组成,每个可屏蔽中断占用8bit,这样总共可以表示15*4=60 个可屏蔽中断。刚好和STM32 的可屏蔽中断数相等。IPR[0]的[31~24],[23~16],[15~8],[7~0]分别对应中中断3~0,依次类推,总共对应60 个外部中断。而每个可屏蔽中断占用的8bit 并没有全部使用,而是只用了高4 位。这4 位,又分为抢占优先级和子优先级。抢占优先级在前,子优先级在后。而这两个优先级各占几个位又要根据SCB->AIRCR 中中断分组的设置来决定。

这里简单介绍一下 STM32 的中断分组:STM32 将中断分为5 个组,组0~4。该分组的设置是由SCB->AIRCR 寄存器的bit10~8 来定义的。具体的分配关系如下表所示:

优先级具体详解请详见CM3权威指南第108页。

通过这个表,我们就可以清楚的看到组 0~4 对应的配置关系,例如组设置为3,那么此时所有的60 个中断,每个中断的中断优先寄存器的高四位中的最高3 位是抢占优先级,低1 位是响应优先级。每个中断,你可以设置抢占优先级为0~7,响应优先级为1 或0。抢占优先级的级别高于响应优先级。而数值越小所代表的优先级就越高。

MY_NVIC_PriorityGroupConfig(u8 NVIC_Group):该函数的参数NVIC_Group 为要设置的分组号,可选范围为0~4,总共5 组。如果参数非法,将可能导致不可预料的结果。

temp1=(~NVIC_Group)&0x07;//取后三位

假设分组为第3组,则NVIC_Group=3=0000 0011,~NVIC_Group=1111 1100. ~NVIC_Group &0x07=0000 0100.

赋给temp1=0000 0000 0000 0000 0000 0000 0000 0100(u32)

temp1<<=8;

此时左移8位后temp1=0000 0000 0000 0000 0000 0100 0000 0000

temp=SCB->AIRCR; //读取先前的设置

temp&=0X0000F8FF; //清空先前分组

设先前设置为:xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx

与:0000 0000 0000 0000 1111 1000 1111 1111相与。

=0x0000F8FF= 0000 0000 0000 0000 1111 1000 1111 1111

使得SCB->AIRCR[10:8]为零,从而就达到分组清零的目的。

temp|=0X05FA0000; //写入钥匙

通过上面的介绍我们知道SCB->AIRCR 的修改需要通过在高16 位写入

0X05FA 这

个密钥才能修改的,故在设置AIRCR 之前,应该把密钥加入到要写入的内容的高16 位,以保证能正常的写入AIRCR。在修改AIRCR 的时候,我们一般采用读->改->写的步骤,来实现不改变AIRCR 原来的其他设置。以上就是

MY_NVIC_PriorityGroupConfig 函数设置中断优先级分组的思路。

temp|=temp1;

把上面左移8位得到的分组赋给temp,即SCB->AIRCR[10:8]为100,即得到上面的假设第3组。

SCB->AIRCR=temp;//设置分组

最后把这个分组写入AIRCR中,完成分组的设置。

//设置NVIC

//NVIC_PreemptionPriority:抢占优先级

//NVIC_SubPriority :响应优先级

//NVIC_Channel :中断编号

//NVIC_Group :中断分组 0~4

//注意优先级不能超过设定的组的范围!否则会有意想不到的错误

//组划分:

//组0:0位抢占优先级,4位响应优先级

//组1:1位抢占优先级,3位响应优先级

//组2:2位抢占优先级,2位响应优先级

//组3:3位抢占优先级,1位响应优先级

//组4:4位抢占优先级,0位响应优先级

//NVIC_SubPriority和NVIC_PreemptionPriority的原则是,数值越小,越优先//CHECK OK

//100329

void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group)

{

u32 temp;

u8 IPRADDR=NVIC_Channel/4; //每组只能存4个,得到组地址

u8 IPROFFSET=NVIC_Channel%4;//在组内的偏移

IPROFFSET=IPROFFSET*8+4; //得到偏移的确切位置

MY_NVIC_PriorityGroupConfig(NVIC_Group);//设置分组

temp=NVIC_PreemptionPriority<<(4-NVIC_Group);

temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);

temp&=0xf;//取低四位

if(NVIC_Channel<32)NVIC->ISER[0]|=1<

else NVIC->ISER[1]|=1<<(NVIC_Channel-32);

NVIC->IPR[IPRADDR]|=temp<

解释:这个函数是NVIC 设置函数MY_NVIC_Init ,该函数有4 个参数,分别为:

NVIC_PreemptionPriority 、NVIC_SubPriority 、NVIC_Channel 、NVIC_Group 。第一个参数NVIC_PreemptionPriority 为中断抢占优先级数值,第二个参数NVIC_SubPriority 为中断子优先级数值,前两个参数的值必须在规定范围内,否则也可能产生意想不到的错误。第三个参数NVIC_Channel 为中断的编号(范围为0~59),最后一个参数NVIC_Group 为中断分组设置(范围为0~4)。

IPR[0]的[31~24],[23~16],[15~8],[7~0]分别对应中中断3~0

IPR[1]的[31~24],[23~16],[15~8],[7~0]分别对应中中断7~4

.

.

.

IPR[14]的[31~24],[23~16],[15~8],[7~0]分别对应中中断59~56

u8 IPRADDR=NVIC_Channel/4; //每组只能存4个,得到组地址

假如是中断7,则IPRADDR=1,即我们用的是IPR[1]。

u8 IPROFFSET=NVIC_Channel%4;//在组内的偏移

中断7对应的偏移是3。

IPROFFSET=IPROFFSET*8+4; //得到偏移的确切位置

那就是到[31~24]。注意,每个中断的8位只用了它的高4位,所以是+4.其实是[31~28].

MY_NVIC_PriorityGroupConfig(NVIC_Group);//设置分组

参照前面的分析。

temp=NVIC_PreemptionPriority<<(4-NVIC_Group);

假设设置分组3,假如NVIC_PreemptionPriority=0000 0011,左移1位,temp=0000 0000 0000 0000 0000 0000 0000 0110.

temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);

0000 1111右移3位是:0000 0001,然后与0000 0001(1位相应优先级数值设为1),得0000 0001,然后与temp相或为:0000 0111. temp=0000 0000 0000 0000 0000 0000 0000 0111.

temp&=0xf;//取低四位

此时temp=0000 0000 0000 0000 0000 0000 0000 0111.

if(NVIC_Channel<32)NVIC->ISER[0]|=1<

else NVIC->ISER[1]|=1<<(NVIC_Channel-32);

使能中断位,这个很好理解。

NVIC->IPR[IPRADDR]|=temp<

假如还是中断7,则IPROFFSET=28,则temp左移28位为

0111 0000 0000 0000 0000 0000 0000 0000,此时IPR[1]的[31~28]位是0111.

//外部中断配置函数

//只针对GPIOA~G;不包括PVD,RTC和USB唤醒这三个

//参数:GPIOx:0~6,代表GPIOA~G;BITx:需要使能的位;TRIM:触发模式,1,下降沿;2,上升沿;3,任意电平触发

//该函数一次只能配置1个IO口,多个IO口,需多次调用

//该函数会自动开启对应中断,以及屏蔽线

//待测试...

void Ex_NVIC_Config(u8 GPIOx,u8 BITx,u8 TRIM)

{

u8 EXTADDR;

u8 EXTOFFSET;

EXTADDR=BITx/4;//得到中断寄存器组的编号

EXTOFFSET=(BITx%4)*4;

RCC->APB2ENR|=0x01;//使能io复用时钟

AFIO->EXTICR[EXTADDR]&=~(0x000F<

AFIO->EXTICR[EXTADDR]|=GPIOx<

GPIOx.BITx

//自动设置

EXTI->IMR|=1<

//EXTI->EMR|=1<

if(TRIM&0x01)EXTI->FTSR|=1<

if(TRIM&0x02)EXTI->RTSR|=1<

}

解释:该函数为 Ex_NVIC_Config,该函数有3 个参数:GPIOx 为GPIOA~G(0~6),在sys.h 里面有定义。代表要配置的IO 口。BITx则代表这个IO 口的第几位。TRIM 为触发方式,低2 位有效(0x01 代表下降触发;0x02 代表上升沿触发;0x03 代表任意电平触发)。

STM32 的19 个外部中断为:线0~15:对应外部IO 口的输入中断。

因为STM32 任何一个IO 口都可以配置成中断输入口,但是IO 口的数目

远大于中断线数(16 个)。于是STM32 就这样设计,GPIOA~GPIOG 的[15:0]分别对应中断线15~0。这样每个中断线对应了最多7 个IO 口,以线0为例:它对应了GPIOA.0、PIOB.0、GPIOC.0、GPIOD.0、GPIOE.0、GPIOF.0、GPIOG.0。而中断线每次只能连接到1 个IO 口上,这样就需要EXTICR来决定对应的中断线配置到哪个GPIO上了。

EXTICR[0]的[3:0]只能存放GPIOA.0~G.0--------------线0;

EXTICR[0]的[7:4]只能存放GPIOA.1~G.1--------------线1;

.

.

.

EXTICR[3]的[15:12]只能存放GPIOA.15~G.15-----------线15;

EXTADDR=BITx/4;//得到中断寄存器组的编号

假设是GPIOA的第5口,则EXTADDR=1,即选择EXTICR[1]。

EXTOFFSET=(BITx%4)*4;

假设是GPIOA的第5口,则EXTOFFSET=4,即选择EXTICR[1]的[7:4].

RCC->APB2ENR|=0x01;//使能io复用时钟

这个很容易理解。

AFIO->EXTICR[EXTADDR]&=~(0x000F<

0x000F左移4位是0x00F0,取个反即0XFF0F,正好是[7:4]清零。

AFIO->EXTICR[EXTADDR]|=GPIOx<

GPIOB=1,左移4位,就是0001 0000,对应[7:4]=0001,正好选择PB口。IMR:中断屏蔽寄存器。这是一个32 寄存器。但是只有前19 位有效。当位x 设置为1 时,则开启这个线上的中断,否则关闭该线上的中断。

EMR:事件屏蔽寄存器,同IMR,只是该寄存器是针对事件的屏蔽和开启。

EXTI->IMR|=1<

把位和中断线对应起来,这个容易理解。

if(TRIM&0x01)EXTI->FTSR|=1<

if(TRIM&0x02)EXTI->RTSR|=1<

//不能在这里执行所有外设复位!否则至少引起串口不工作.

//把所有时钟寄存器复位

void MYRCC_DeInit(void)

{

RCC->APB1RSTR = 0x00000000;//复位结束

RCC->APB2RSTR = 0x00000000;

RCC->AHBENR = 0x00000014; //睡眠模式闪存和SRAM时钟使能.其他关闭.

RCC->APB2ENR = 0x00000000; //外设时钟关闭.

RCC->APB1ENR = 0x00000000;

RCC->CR |= 0x00000001; //使能内部高速时钟HSION

RCC->CFGR &= 0xF8FF0000; //复位

SW[1:0],HPRE[3:0],PPRE1[2:0],PPRE2[2:0],ADCPRE[1:0],MCO[2:0]

RCC->CR &= 0xFEF6FFFF; //复位HSEON,CSSON,PLLON

RCC->CR &= 0xFFFBFFFF; //复位HSEBYP

RCC->CFGR &= 0xFF80FFFF; //复位PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE

RCC->CIR = 0x00000000; //关闭所有中断

//配置向量表

#ifdef VECT_TAB_RAM

MY_NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);

#else

MY_NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);

#endif

}

解释:关于复位用到得一系列寄存器参考“免积分-STM32-中文资料参考”的第51页后。

//THUMB指令不支持汇编内联

//采用如下方法实现执行汇编指令WFI

__asm void WFI_SET(void)

{

WFI;

}

解释:这里用到了一个WFI_SET();函数,该函数其实是在C 语言里面嵌入一条汇编指令,因为CM3 内核的STM32 支持的THUMB 指令,并不能内嵌汇编,所以需要通过这个方法来实现汇编代码的嵌入。

/进入待机模式

void Sys_Standby(void)

{

SCB->SCR|=1<<2;//使能SLEEPDEEP位 (SYS->CTRL)

RCC->APB1ENR|=1<<28; //使能电源时钟

PWR->CSR|=1<<8; //设置WKUP用于唤醒

PWR->CR|=1<<2; //清除Wake-up 标志

PWR->CR|=1<<1; //PDDS置位

WFI_SET(); //执行WFI指令

}

解释:STM32 提供了3 种低功耗模式,以达到不同层次的降低功耗的目的,这三种模式如下:

睡眠模式(CM3 内核停止工作,外设仍在运行);

停止模式(所有的时钟都停止);

待机模式;

其中睡眠模式又分为有深度睡眠和睡眠之分。Sys_SleepDeep 函数用来使STM32 进入待机

模式,在该模式下,STM32 所消耗的功耗最低。下面是一个STM32 的低功耗一览表:

下表展示了如何进入和退出待机模式,关于待机模式的更详细介绍请参考《STM32 参考手册》第4.3 节(40 页)。

//系统软复位

void Sys_Soft_Reset(void)

{

SCB->AIRCR =0X05FA0000|(u32)0x04;

}

解释:软复位归根到底就是对SCB-> AIRCR 进行了一次操作,只要把位2置位即可。

//JTAG模式设置,用于设置JTAG的模式

//mode:jtag,swd模式设置;00,全使能;01,使能SWD;10,全关闭;

void JTAG_Set(u8 mode)

{

u32 temp;

temp=mode;

temp<<=25;

RCC->APB2ENR|=1<<0; //开启辅助时钟

AFIO->MAPR&=0XF8FFFFFF; //清除MAPR的[26:24]

AFIO->MAPR|=temp; //设置jtag模式

}

解释:

STM32 支持JTAG 和SWD 两种仿真接口,他们和普通的IO 口共用,当需要使用普通IO口的时候,则必须先禁止JTAG/SWD。STM32 在默认状态下是开启JTAG 的,所以那些和JTAG共用的IO 口,在默认状态下是不能做普通IO 口使用的。我们可以通过AFIO_MAPR 寄存器的24~26 位来修改STM32 的JTAG 配置,从而切换为普通IO 口或者其他状态。AFIO_MAPR 寄存器的第24~26 位描述如下图所示:

通过该函数,我们就可以方便的设置JTAG 的模式。这里顺便提一下,JTAG 和普通IO 口,可以在仿真的时候,分时复用,不过在您禁止了JTAG 的地方(先禁止,后开启),您必须一步跳过去,也就是这部分代码,您不要执行到里面去观察,直接跳过。这样,您的JTAG 可以在不断线的情况下,继续调试下面的代码。

RCC->APB2ENR|=1<<0; //开启辅助时钟

//系统时钟初始化函数

//pll:选择的倍频数,从2开始,最大值为16

void Stm32_Clock_Init(u8 PLL)

{

unsigned char temp=0;

MYRCC_DeInit(); //复位并配置向量表

RCC->CR|=0x00010000; //外部高速时钟使能HSEON

while(!(RCC->CR>>17));//等待外部时钟就绪

RCC->CFGR=0X00000400; //APB1=DIV2;APB2=DIV1;AHB=DIV1; PLL-=2;//抵消2个单位

RCC->CFGR|=PLL<<18; //设置PLL值 2~16

RCC->CFGR|=1<<16; //PLLSRC ON

FLASH->ACR|=0x32; //FLASH 2个延时周期

RCC->CR|=0x01000000; //PLLON

while(!(RCC->CR>>25));//等待PLL锁定

RCC->CFGR|=0x00000002;//PLL作为系统时钟

while(temp!=0x02) //等待PLL作为系统时钟设置成功{

temp=RCC->CFGR>>2;

temp&=0x03;

}

}

解释:

MYRCC_DeInit(); //复位并配置向量表

调用复位与配置向量表函数

RCC->CR|=0x00010000; //外部高速时钟使能HSEON

while(!(RCC->CR>>17));//等待外部时钟就绪

第17位右移17位,正好在第0位,如果第17位为零,则整个数字为零,因为上面刚刚复位过的,所以17位前面都是为零,如果第17位为1,即外部高速时钟就绪,那就不为0,不为0就可以执行以下的语句了。

RCC->CFGR=0X00000400; //APB1=DIV2;APB2=DIV1;AHB=DIV1;

RCC->CFGR=0000 0000 0000 0000 0000 0100 0000 0000,[10:8]为100,那APB1就是2分频,APB2不分频,同理AHB也不分频。

PLL-=2;//抵消2个单位

RCC->CFGR|=PLL<<18; //设置PLL值 2~16

假如PLL是9倍频,那9-2=7,即0111,正好对应PLL 9倍频输出。然后左移18位放置到对应位置去。

RCC->CFGR|=1<<16; //PLLSRC ON

使CFGR得位16置1,即HSE时钟作为PLL输入时钟。

FLASH->ACR|=0x32; //FLASH 2个延时周期

FLASH寄存器结构,FLASH_TypeDef和OB_TypeDef,在文件“stm32f10x_map.h”中定义如下: typedef struct

{ vu32 ACR;

vu32 KEYR;

vu32 OPTKEYR;

vu32 SR;

vu32 CR;

vu32 AR;

vu32 RESERVED;

vu32 OBR;

vu32 WRPR;

} FLASH_TypeDef;

这是和FLASH的设计有关的,因为FLASH速度比较低,访问FLASH不能马上得到数据,所以需要等待。

和时钟频率有关的.这个资料要看STM32的AN才有. 当频率大于36M的时候,就需要2个延时.当频率少于36M的时候,可以不要. 貌似是36M,不记得了...(原子)

RCC->CR|=0x01000000; //PLLON

这个对照RCC->CR寄存器便可以理解。

{

temp=RCC->CFGR>>2;

temp&=0x03;

}

右移2位再取它的低8位和0x03相与,然后判断是不是等于0x02,其实为了让

位3:2由硬件置成10时才算设置成功。

相关文档