关于stm:上海航芯-智能设备防盗版解决方案分享

随着科技的提高与倒退,身边的电子设备变得日趋智能,这些智能设施在使得人们工作与生存变得便捷的同时,产品的版权及安全性正受到威逼。为了保护设施制造商的利益和品牌价值,也为了爱护消费者应用产品的品质和服务保障,智能设施的平安和防伪将变得非常重要,爱护它也就是爱护了本身的平安。 上海航芯智能设施防盗版解决方案采纳金融级平安芯片ACL16_S,反对多种对称、非对称、散列等明码算法,能够宽泛实用于智能家居、汽车电子、医疗设施、电子烟耗材等畛域。 1 计划特点 采纳金融级平安芯片ACL16_S,安全性更高 单芯片计划,无需外围器件,带来更低的BOM老本 每个设施采纳一机一密的形式,Wafer级根密钥预置,从源头进行密钥爱护 反对SPI、UART、I2C、ISO7816、SWI复线等多种通信接口,便于与多种零碎主机进行集成 丰盛的软件库配套,易于多种平台系统集成 小尺寸封装反对,便于PCB板的硬件集成 反对多种低功耗模式,满足电池智能设施的续航要求 2 典型利用 硬件电路防抄板 原厂配件认证(电池、数据线) IoT设施防伪 电源适配器 汽车电子 智能家居 软件IP爱护 License治理 3 计划框图 Host:能够是零碎板上的主芯片,也能够是云端的后盾服务器。 Device:能够是航芯的平安芯片,也能够是嵌入航芯平安芯片的设施。 反对不同认证形式的平安芯片 4 芯片个性 反对1.8V-3.3V电压供电 反对ECC椭圆曲线算法,反对NIST B-163曲线和P256曲线 反对HMAC认证,反对SHA-256散列算法 反对SPI、UART、I2C、ISO7816、SWI复线等多种通信接口 反对客户敏感代码执行 反对TSSOP8、DFN8、SOT23、WLCSP等多种封装规格 动静功耗小于3mA,待机功耗小于1uA 5 平安个性 金融级平安芯片,合乎EAL5+安全级别 128位惟一序列号 被动屏蔽层 环境异常检测模块 防SPA/DPA攻打 防谬误注入攻打

March 26, 2022 · 1 min · jiezi

关于stm:国产品牌NS32F103CBT6完美替代STM32F103C8T6

NS32F103x8 和 NS32F103xB 标准型 MCU 系列应用高性能的 ARM Cortex-M3 32 位的 RISC 内核,工作频率为 72MHz,内置高速存储器(高达 128K 字节的闪存和 20K 字节的 SRAM),丰盛的加强 I/O 端口和联接到两条 APB 总线的外设。其中蕴含 2 个 12 位 ADC、3 个通用 16 位定时器和 1 个 PWM 定时器, 此外,还蕴含规范和先进的通信接口:多达 2 个 I 2C 接口和 SPI 接口、3 个 USART 接口、1 个 USB 接口和1 个 CAN 接口。NS32F103x8 和 NS32F103xB 标准型 MCU 系列产品供电电压为 2.0V 至 3.6V,-40°C 至+85°C 的工作温度范畴以及-40°C 至+105°C 的扩大温度范畴, 一系列的省电模式保障低功耗利用的要求。NS32F103x8 和 NS32F103xB 标准型系列产品提供包含从 36 脚至 100 脚的 4 种不同封装模式;依据不同的封装模式,器件中的外设配置不尽相同。上面给出了该系列产品中所有外设的根本介绍。这些丰盛的外设配置,使得 NS32F103x8 和 NS32F103xB 标准型系列微控制器可使用于多种利用场合:电机驱动和利用管制医疗和手持设施PC 游戏外设和 GPS 平台 ...

March 26, 2022 · 1 min · jiezi

关于stm:32和51单片机的定时计数器

51单片机的定时计数器定时/计数器的核心部件是一个加法(或减法)计数器;若计数脉冲来自零碎时钟,则为定时形式;若计数脉冲来自单片机内部引脚,则为计数形式。 根本介绍定时器: 定时器是SOC的外部外设。定时器就是CPU的闹钟。计数器: 单片机实现定时器其实质是用计数器来实现的。计数器能够计算内部脉冲的个数。当单片机计算外部脉冲个数时就相当于定时器,当计算内部脉冲个数就相当于计数器。加法计数器和减法计数器:(51单片机是加法计数器) 加法计数器:从咱们给定的值开始加,加到溢出,而后触发中断。 例如:16位定时器最大计数65535次,如果咱们想计数50000次,那么设置的TH和TL应设为65535-50000 = 15535。减法计数器;从咱们给定的值开始减,减到0就溢出,而后触发中断。 例如:16位定时器最大计数65535次,如果咱们想计数50000次,那么设置的TH和TL应设为50000。计算TL和TH: 首先确定定时工夫,time(例如50ms)。确定外部时钟周期,因为是12T模式,晶振12MHz,所以外部频率1MHz,周期1us。定时计个数 = time ÷ 周期。(50000)TL1 = 个数 % 256(取余);TH1 = 个数 / 256(取整)。工作流程设置定时器时钟源(作定时器应用时,须要外部的脉冲,这个脉冲来源于时钟源)初始化定时器相干寄存器。设置定时工夫(计数个数)设置中断处理程序。关上定时器。运行时:定时器计数到设置值后产生中断,执行中断处理程序。定时/计数器相干寄存器。管制寄存器TCON TF1:定时器/计数器T1溢出标记位。T1被容许计数后,从初值开始加一,计数实现后由硬件置位,收回中断请求;中断响应后硬件主动复位。TR1:定时器T1容许管制位,由软件置位和清零。GATE(TMOD.7)= 0,TR1 = 1时才容许T1开始计数。IE1:内部中断1申请源标记。IE1 = 1,内部中断向CPU申请中断,CPU响应后由硬件清零。、IT1:内部中断1触发形式管制位。IT1 = 0时,内部中断1为低电平触发形式;IT1 = 1时,内部中断1为高电平触发形式。工作模式寄存器TMOD GATE(TMOD.7):与TCON.6(TR1)配合管制定时器运行C/T(TMOD.6):管制定时器1用作定时器还是计数器。清零用作定时器,置一用作计数器。M1/M0(TMOD.5/TMOD4):定时计数器模式抉择位。(00)模式0(13位定时器/计数器); (01)模式1(16位定时器/计数器模式); (10)模式2(8位主动重装模式); (11)模式3(两个8位定时器/计数器)。示例代码//TIM1定时器初始化void TIM1_Init(){ TMOD = 0x10; // T0设置工作在定时器模式下,模式一 16位定时器 TL1 = (65535 - 50000) % 256; TH1 = (65535 - 50000) / 256; TR1 = 1; // 开启计数器,开始计数了 ET1 = 1; // 开启T1中断 EA = 1; // 开启中断总开关 count = 10; // 10次,对应500ms}//TIM1中断处理程序;定时500msvoid timer1_isr(void) interrupt 1 using 1{ TL1 = (65535 - 50000) % 256; TH1 = (65535 - 50000) / 256; // 手工重装载计数值 //因为模式一不能主动重装载,所以要手工重装载计数值。 if (count-- == 0) { // 阐明曾经中断了10次了,500ms到了,该干活了 LED = !LED; // LED取反 count = 10; }}STM32单片机的定时/计数器独立看门狗(IWDG)当计数器达到给定的超时值时会产生零碎复位。独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即便主时钟产生故障它也依然无效。独立看门狗(IWDG)是减法计数器。看门狗被激活后,则在计数器计数至0x000时产生复位(复位的意思是指从0xfff开始递加)独立看门狗能够在任何时候进行喂狗操作。喂狗后,计数器从设定的值开始计数。IWDG最适宜利用于那些须要看门狗作为一个在主程序之外(次要是为了避免程序跑飞),可能齐全独立工作,并且对工夫精度要求较低的场合。窗口看门狗(WWDG)当计数器达到给定的超时值时会产生零碎复位或触发一个中断。窗口看门狗由从APB1时钟分频后失去的时钟驱动。窗口看门狗(WWDG)是减法计数器。窗口看门狗(WWDG)喂狗工夫有严格控制。必须要在规定的工夫内(窗口)喂狗才无效。如果在其余工夫喂狗则会产生复位,如果在窗口没有喂狗,则计数完后也会产生复位。WWDG最适宜那些要求看门狗在准确计时窗口起作用的应用程序。通用定时器(TIMx)((TIM2、TIM3、TIM4、TIM5)TIMx简介16位向上(加法计数)、向下(减法计数)、向上/向下主动装载计数器。向上/向下计数(地方对齐模式):计数器从0加到(设定值-1)触发溢出中断,再从(设定值-1)减到1触发下溢中断。加法计数和减法计数:例如想计数500次,加法计数器是从0开始计数到500,而减法计数器是从500减到0。性能:输出捕捉、输入比拟、PWM。16位可编程(能够实时批改)预分频器,计数器时钟频率的分频系数为1~65536之间的任意数值。(计数器的时钟频率是由下级频率通过预分频器分频失去的,下级频率每个定时器可能不同,可能是APB1或APB2,下级频率设置办法请查看另外一篇文章“STM32时钟体系”)计数器、主动装载寄存器和预分频器寄存器能够由软件读写,在计数器运行时仍能够读写。计数器由预分频器的时钟输入CK_CNT驱动,仅当设置了计数器TIMx_CR1寄存器中的计数器使能位(CEN)时,CK_CNT才无效。主动重装载寄存器、预装载寄存器、影子寄存器、计数器关系:(集体了解,不肯定对) ...

February 15, 2022 · 1 min · jiezi

关于stm:基于STM32F1单片机的通信方式

通用同步异步收发器(USART)USART介绍全双工的异步通信。接口通过三个引脚与其余设施连贯在一起(接管RX、发送TX、时钟输入CK)(任何USART双向通信至多须要RX和TX)发送方为同步传输提供时钟。发送和接管由一共用的波特率发生器驱动,当发送器和接收器的使能位别离置位时,别离为其产生时钟。波特率 应用分数波特率发生器零碎发送和接管共用的可编程波特率,最高达4.5Mbits/s12位整数和4位小数的示意办法。只有USART1应用PCLK2(即APB2最高72MHz)。其它USART应用PCLK1(即APB1最高36MHz)。可编程数据字长度(8位或9位)(8数据+n进行位/9数据+n进行位)(数据位最初一个可能是奇偶校验位)(数据最低无效位在前)可配置的进行位-反对1或2个进行位。发送和接收数据流程:(数据寄存器USART_DR蕴含发送寄存器TDR和接管寄存器RDR) 发送数据:零碎进行写操作将数据写入发送寄存器TDR,而后TDR将数据移送到发送移位寄存器中,再由发送移位寄存器送入编解码模块中编码后从TX输入。接收数据;数据从RX进入,先到编解码模块中解码后送入接管移位寄存器,而后再到接管寄存器RDR中供零碎进行读操作。当发送使能位(TE)被设置时,发送移位寄存器中的数据在TX脚上输入,相应的时钟脉冲在CK脚上输入。留神:在数据传输期间不能复位TE位,否则将毁坏TX脚上的数据,因为波特率计数器进行计数。正在传输的以后数据将失落。分数波特率的计算波特率 = PCK /(16*USARTDIV)(USARTDIV是波特比率寄存器中的值换算失去,即分频系数)已知USARTDIV = 25.62;求波特比率寄存器USART_BRR该写入的值。 DIV_Fraction = 16*0.62 = 9.92。最靠近的整数是:10 = 0xADIV_Mantissa = 取整(25.620) = 25 = 0x019。(整数局部是12位所以是0x019,写0x19也行,这里是为了好分别)、所以USART_BRR = 0x019A(写作0x19A也行)USART的中断请求USART的各种中断事件被连贯到同一个中断向量以下各种状况会触发中断:(如果设置了对应的使能管制位,这些事件就能够产生各自的中断) 发送期间:发送实现、革除发送、发送数据寄存器为空。接管期间:闲暇总线检测、溢出谬误、接收数据寄存器非空、校验谬误、LIN断开符号检测、乐音标记(仅在多缓冲器通信)和帧谬误(仅在多缓冲器通信)。USART寄存器状态寄存器(USART_SR) 复位值:0x00C0TXE:发送寄存器DTR是否为空标记位。 当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。如果管制寄存器USART_CR1中的TXEIE为1,则产生中断。对数据寄存器USART_DR的写操作,硬件会将该位清零。1:数据曾经被转移到移位寄存器。TC:发送实现标记位。 当一帧数据发送实现后,并且TXE=1时,该位被硬件置一。如果管制寄存器USART_CR1中的TXEIE为1,则产生中断。由软件序列革除该位(先读USART_SR,而后写入USART_DR)1:发送实现。RXNE:查看接管移位寄存器是否为空标记位。 当接管移位寄存器中的数据被转移到接收数据寄存器RDR中时,该位被硬件置位(接管移位寄存器中为空)如果管制寄存器USART_CR1中的RXNEIE为1,则产生中断。对数据寄存器USART_DR的读操作能够将该位清零。1:收到数据,能够读出。IDLE:监测到总线闲暇标记位。 当检测到总线闲暇时,该位被硬件置位。如果USART_CR1中的IDLEIE为1,则产生中断。由软件序列革除该位(先读USART_SR,而后读USART_DR)。1:检测到闲暇总线。数据寄存器(USART_DR) 复位值:不确定DR:数据值,蕴含了发送或接管的数据。波特比率寄存器(USART_BRR) 复位值:0x0000DIV_Mantissa:USARTDIV的整数局部DIV_Fraction:USARTDIV的小数局部管制寄存器 1(USART_CR1) 复位值:0x0000UE:USART使能位。该位由软件设置和清零。(0:USART分频器和输入被禁止)M:设置传输字长,由软件对其设置和清零(0:8个数据位。1:9个数据位)PCE:测验管制使能(1:使能校验管制)PS:校验抉择(0:偶校验)PEIE:PE中断使能(1:当USART_SR中的TXE为1时,产生USART中断)TCIE:发送实现中断使能(1:当USART_SR中的TC为1时,产生USART中断)RXNEIE:接管移位寄存器为空的中断使能(1:当USART_SR中的ORE或者RXNE为1时,产生USART中断)IDLEIE:总线闲暇IDLE中断使能(该位由软件设置或革除)(1:当USART_SR中的IDLE为1时,产生USART中断)TE:发送使能(1:使能发送)RE:接管使能(1:使能接管,并开始搜查RX引脚上的起始位)管制寄存器 2(USART_CR2) 复位值:0x0000STOP:进行位(UART4和UART5不能用0.5进行位和1.5进行位) 00:1个进行位。01:0.5个进行位。10:2个进行位。11:1.5个进行位CLKEN:时钟使能(0:禁止CK引脚)代码示例USART初始化设置/******************************************************************************** 函 数 名 : USART1_Init* 函数性能 : USART1初始化函数* 输 入 : bound:波特率* 输 出 : 无*******************************************************************************/ void USART1_Init(u32 bound){ //GPIO端口设置 GPIO_InitTypeDef GPIO_InitStructure; //申明GPIO对象 USART_InitTypeDef USART_InitStructure; //申明串口对象 NVIC_InitTypeDef NVIC_InitStructure; //申明嵌套断的对象 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); /* 配置GPIO的模式和IO口 */ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX //串口输入PA9 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输入 GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化串口输入PA9*/ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX //串口输出PA10 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模仿输出 GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化串口输出PA10*/ //USART1 初始化设置 USART_InitStructure.USART_BaudRate = bound;//波特率设置 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式 USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个进行位 USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流管制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式 USART_Init(USART1, &USART_InitStructure); //初始化串口1 USART_Cmd(USART1, ENABLE); //使能串口1 USART_ClearFlag(USART1, USART_FLAG_TC); //革除串口的挂起标记 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相干中断 //Usart1 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //串口1中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; //抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //依据指定的参数初始化VIC寄存器、 }串口的中断函数/******************************************************************************** 函 数 名 : USART1_IRQHandler* 函数性能 : USART1中断函数* 输 入 : 无* 输 出 : 无*******************************************************************************/ void USART1_IRQHandler(void) //串口1中断服务程序{ u8 r; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接管中断 { r =USART_ReceiveData(USART1);//(USART1->DR); //读取接管到的数据 USART_SendData(USART1,r); // 将接管到的数据再发送回去 while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET); } USART_ClearFlag(USART1,USART_FLAG_TC);} I2C通信之EEPROMI2C特点遵循着与51单片机雷同的I2C协定。接口通过数据引脚(SDA)和时钟引脚(SCL)连贯到I2C总线(数据引脚SDA用于数据传输,时钟引脚SCL用于收发数据的同步)I2C模块接管和发送数据,并将数据从串行转换成并行,或并行转换成串行。I2C主设施性能: ...

February 14, 2022 · 4 min · jiezi

关于stm:基于51单片机的通信方式

什么是串行通信通信分串行和并行:串行是指用一根线通信,并行是指用多根线同时通信。这种通信也能够称为:串行通信、串口通信、UART、USART。特点:异步、串行、全双工。工作形式:有三根线(GND/RXD接管线/TXD发送线);数据在发送方和接管方的CPU中都是以字节为单位进行解决的;数据在通信线上以位为单位一一bit传输。串行通信次要概念:起始位、数据位、奇偶效验位、进行位、波特率(一秒钟发送多少bit位,发送方和接管方波特率必须一样)串行通信性能是SOC的一个外部外设提供的,与CPU自身无关。STC51串行通信相干寄存器管制寄存器PCON和SCON串行管制寄存器SCON:串行管制寄存器SCON用于抉择串行通信的工作形式和某些管制性能。 SM0/FE:当PCON寄存器中的SMODO位为1时,该位用于帧谬误检测。当检测到一个有效进行位时,通过UART接收器设置该位。它必须由软件清零。当PCON寄存器中的SMODO位为0时,该位和SM1一起指定串行通信的工作形式(SM0、SM1)。 0 0 :工作形式0;同步移位串行形式;波特率是 SYSclk/12.0 1 :工作形式1;8位UART,波特率可变;1 0 :工作形式2;9位UART;1 1 :工作形式3;9位UART;波特率可变;REN:容许/禁止串行接管管制位。(由软件置位和复位)TI:发送数据时的中断请求标记位。当发送完一帧数据后硬件主动置位,即TI=1。RI:接收数据时的中断请求标记位。当接管完一帧数据后硬件主动置位,即RI=1。电源管制寄存器PCON:用于抉择波特率是否加倍 SMOD:波特率抉择位。SMOD=1,加倍;SMOD=0,不加倍。SMOD0:帧谬误检测无效管制位。中断容许寄存器IE EA : CPU的总中断容许管制位。ES:串行口中断容许位。定时器/计数器管制寄存器TCON TR1:定时器T1的运行管制位。该位由软件置位和清零。TR1=1时开始计数,TR1=0时禁止计数。串行口工作模式次要利用串行口工作模式1:8位UART,波特率可变。 当软件设置SCON的SMO、SM1为“01”时,串行通信则以模式1工作。一帧信息为10位:1位起始位,8位数据位(低位在先)和1位进行位。TXD为发送信息,RXD为接管信息。一帧信息发送或接管实现后,就会发动中断请求,置位RI或TI。波特率计算公式 SMOD为0或1。SYSclk为零碎时钟频率。(我的是12MHz)TH1为主动重装载值。TH1取整数。留神;计算波特率时,256-TH1的值必须要是整数左近零点零几的地位才行,差太多可能会造成乱码。(差了零点2都可能会乱码) 代码示例串口初始化 // 串口初始化函数// 预设一个串口条件:8数据位、1进行位、0校验位、波特率9600// 初始化的次要工作就是去设置相干的寄存器void uart_init(void){ SCON = 0x50; // 01010000 串口工作在模式1(8位串口)、容许接管 PCON = 0x00; // 波特率不加倍 // 通信波特率相干的设置 TMOD = 0x20; // 用作定时器,设置T1为模式2(8位主动重装载) TH1 = 243; //2×12000000÷32÷12÷4800=13.0208,256-TH1=13,TH=243。 TL1 = 243; // 8位主动重装,当溢出时主动将TH1寄存的值装入TL1中。TH1和TL1必须雷同 TR1 = 1; // 开启T1定时/计数器 ES = 1; //串行口中断容许位 EA = 1; //总中断容许位}发送数据 // 单片机通过串口发送1个字节到电脑端。void uart_send_byte(unsigned char c){ // 第1步,发送一个字节 SBUF = c; // 第2步,先确认串口发送局部没有在忙 while (!TI); // 第3步,软件复位TI标记位 TI = 0;}//单片机发送字符到电脑端void uart_send_string(unsigned char *str){ while (*str != '\0') { uart_send_byte(*str); // 发送1个字符 str++; // 指针指向下一个字符 }}//电脑端发送数据到单片机,单片机接收数据,触发中断,RI=1。void uart_isr(void) interrupt 4 using 1{ unsigned char tmp; if (RI) { tmp = SBUF; // 读取SBUF,其实就是读出了串口接管到的1字节 RI = 0; } uart_send_byte(tmp); //将接管到的数据再发送给电脑端,测试是否接管胜利。}基于51单片机的I2C通信之EEPROM基本知识ROM(只读存储器)、RAM(随机拜访存储器)、PROM(可编程ROM)EPROM(可擦除ROM)、EEPROM(电可擦除ROM)EEPROM在零碎中的存在模式:内置在单片机外部或内部扩大。EEPROM原理图:I2C总线协定规定任何将数据传输到总线的都作为发送器,任何从总线接收数据的器件都作为接收器。数据传输由主器件管制,总线的串行时钟、起始进行条件均由主器件产生。只有在总线非忙时才容许进行数据传输。在数据传送时,过后钟线为高电平,数据线必须为固定状态,不容许有跳变。时钟线为高电平时,数据线的任何电平变动将被当作总线的启动或进行条件。启动条件:启动条件必须在所以操作命令之前发送。时钟线放弃高电平期间,数据线电平从高到低的跳变作为I2C总线的启动信号。进行条件:时钟线放弃高电平期间,数据线从低到高的跳变作为I2C总线的进行信号。操作完结时必须发送进行条件。I2C数据传输方式:I2C总结主CPU和其从属芯片最罕用的接口,尤其是各种传感器。三根控制线:GND、SCL、SDA。串行、电平式。(STM32单片机中也是如此)发送和接管字节时都是从高位开始。总线式构造,能够一对多,总线上能够挂载上百个器件,用从地址来辨别。主从式,由主设施发动通信及总线仲裁,从设施被动响应。通信速率较低,不适宜语音、视频等。I2C代码示例/******************************************************************************** 函 数 名 : I2C_Start()* 函数性能 : 起始信号:在I2C_SCL时钟信号在高电平期间I2C_SDA信号产生一个降落沿* 输 入 : 无* 输 出 : 无* 备 注 : 起始之后I2C_SDA和I2C_SCL都为0*******************************************************************************/void I2C_Start(){ I2C_SDA = 1; I2C_Delay10us(); I2C_SCL = 1; I2C_Delay10us();//建设工夫是I2C_SDA放弃工夫>4.7us I2C_SDA = 0; I2C_Delay10us();//放弃工夫是>4us I2C_SCL = 0; I2C_Delay10us(); }/******************************************************************************** 函 数 名 : I2C_Stop()* 函数性能 : 终止信号:在I2C_SCL时钟信号高电平期间I2C_SDA信号产生一个回升沿* 输 入 : 无* 输 出 : 无* 备 注 : 完结之后放弃I2C_SDA和I2C_SCL都为1;示意总线闲暇*******************************************************************************/void I2C_Stop(){ I2C_SDA = 0; I2C_Delay10us(); I2C_SCL = 1; I2C_Delay10us();//建设工夫大于4.7us I2C_SDA = 1; I2C_Delay10us(); }/******************************************************************************** 函 数 名 : I2cSendByte(uchar num)* 函数性能 : 通过I2C发送一个字节。在I2C_SCL时钟信号高电平期间,* * 放弃发送信号I2C_SDA保持稳定* 输 入 : num ,ack* 输 出 : 0或1。发送胜利返回1,发送失败返回0* 备 注 : 发送完一个字节I2C_SCL=0, 须要应答则应答设置为1,否则为0*******************************************************************************/uchar I2C_SendByte(uchar dat, uchar ack){ uchar a = 0,b = 0;//最大255,一个机器周期为1us,最大延时255us。 // 为了保障时序正确,这里应该加一句 SCL = 0; for(a=0; a<8; a++)//要发送8位,从最高位开始 { I2C_SDA = dat >> 7; //起始信号之后I2C_SCL=0,所以能够间接扭转I2C_SDA信号 dat = dat << 1; I2C_Delay10us(); I2C_SCL = 1; I2C_Delay10us();//建设工夫>4.7us I2C_SCL = 0; I2C_Delay10us();//工夫大于4us } I2C_SDA = 1; // 主设施开释SDA线给从设施去操作 I2C_Delay10us(); I2C_SCL = 1; // 主设施开始了第9个周期 while(I2C_SDA && (ack == 1))//期待应答,也就是期待从设施把I2C_SDA拉低 { b++; if(b > 200) //如果超过200us没有应答发送失败,或者为非应答,示意接管完结 { I2C_SCL = 0; I2C_Delay10us(); return 0; } } I2C_SCL = 0; I2C_Delay10us(); return 1; }/******************************************************************************** 函 数 名 : I2cReadByte()* 函数性能 : 应用I2c读取一个字节* 输 入 : 无* 输 出 : dat* 备 注 : 接管完一个字节I2C_SCL=0*******************************************************************************/uchar I2C_ReadByte(){ uchar a = 0,dat = 0; I2C_SDA = 1; //CPU开释总线,让从设施接管。(51单片机中是这样解决,32中可能有点不同) I2C_Delay10us(); // 按情理这里应该有一个SCL = 0的 for(a=0; a<8; a++)//接管8个位 { I2C_SCL = 1; // 告诉从设施我要开始读了,能够放1bit数据到SDA了 I2C_Delay10us(); dat <<= 1; // 读取的时候是高位在前的 dat |= I2C_SDA; I2C_Delay10us(); I2C_SCL = 0; // 拉低,为下一个bit的周期做筹备 I2C_Delay10us(); } return dat; }EEPROM(AT24C02芯片介绍(最多保留255个字节))器件寻址主器件通过发送一个起始信号启动发送过程,而后发送从器件地址。(从地址是芯片自身定义的)8位从器件地址的高4位固定为1010,接下来的3位为从器件的地址位,最低位为从器件的读写位(1示意对从器件进行读操作,0示意对从器件进行写操作)在主器件发送起始信号和从器件地址后,AT24C02会监督总线,当某一个器件的地址与发送的从地址雷同时,响应一个应答信号(通过SDA线)。应答信号I2C总线数据传输时,每胜利传输一个字节数据后,接收器都必须产生一个应答信号,接收器在第九个时钟周期将SDA拉低,示意曾经收到一个字节数据。当AT24C02工作于被读状态时,在发送一个字节之后会开释总线,并监督总线,如果接管到应答信号,则持续发送数据;若没有接管到应答信号,则进行发送数据。写操作时序图)(ACK就是应答信号)写操作单写一个字节: ...

February 7, 2022 · 3 min · jiezi

关于stm:STM32时钟体系

STM32的时钟总体设计时钟源:纯外部(不精准)、内外部(时钟产生的振荡电路在外部,然而晶振在内部)、纯内部(间接从内部接入一个时钟)。单片机外部有齐全独立的多个时钟。PLL时钟:锁相环电路。性能就是进行倍频。外部设有两套独立时钟:HSx(高速时钟源)和LSx(低速时钟源)。纯外部:HSI、LSI。内外部;HSE、LSE。纯内部:OSC_IN、OSC32_IN(应用较少)红方框中SYSCLK是零碎时钟,是共给CPU的时钟(SYSCLK是多少CPU主频就是多少);之后的局部是配置各个模块的时钟。上电复位后,默认用的是外部时钟(红线门路)(外部时钟不精确) STM32时钟寄存器STM32所有的时钟上电默认是敞开的(即寄存器默认都是0)。下列寄存器图中上面的r、w是可读可写的意思(r:可读,由硬件置位。w:可写)(rw:既可读又可写)时钟管制寄存器(RCC_CR) PLLRDY:PLL时钟就绪标记,PLL锁定后由硬件置一。(PLL倍频不是一瞬间实现的,须要肯定的工夫)(0:PLL未锁定。1:PLL锁定)PLLON:PLL使能,由软件置一和清零。当PLL时钟被用作或被抉择将要作为零碎时钟时,该位不能被清零。(0:PLL敞开。1:PLL使能)HSERDY:内部高速时钟就绪标记。由硬件置一来批示内部4-16MHz振荡器曾经稳固。在HSEON位清零后,该位须要6个内部4-25MHz振荡器周期清零。(0:未就绪。1:就绪)HSEON:内部高速时钟使能。由软件置一和清零。(0:HSE振荡器敞开。1:HSE振荡器关上)HSIRDY:外部高速时钟就绪标记。由硬件置一来批示外部8MHz振荡器曾经稳固。在HSION位清零后,该位须要6个外部8MHz振荡器周期清零。(0:外部8MHz振荡器未就绪,1:外部8MHz振荡器就绪)HSION:外部高速时钟使能。由软件置一和清零。(0:外部8MHz振荡器敞开。1:外部8MHz振荡器关上)时钟配置寄存器(RCC_CFGR)留神与上图的时钟树绝对应。 USBPRE:USB预分频。由软件置一或清零来产生48MHz的USB时钟。在RCC_APB1ENR寄存器中使能USB时钟之前,必须保障该位曾经无效。如果USB时钟被使能,该位不能被清零。(0:PLL时钟1.5倍分频作为USB时钟。1:PLL时钟间接作为USB时钟)PLLMUL:PLL倍频系数。由软件设置来确定PLL倍频系数。只有在PLL敞开的状况下才可被写入(留神:PLL的输入频率不能超过72MHz)PLLXTPRE:HSE分频器作为PLL输出。(软件置一和清零抉择HSE是否分频)PLLSRC:抉择PLL输出时钟源。(0:抉择HSI经2分频后作为PLL输出时钟。1:抉择HSE时钟作为PLL输出时钟)ADCPRE:ADC预分频。由软件设置。PPRE2:高速APB预分频设置(APB2)。由软件设置预分频系数。PPRE1:低速APB预分频设置(APB1)。由软件设置预分频系数。HPRE: AHB预分频。由软件设置预分频系数。SW:零碎时钟切换(即时钟树中的SW地位)。(00:HSI)(01:HSE)(10:PLL)(11:不可用)时钟中断寄存器 (RCC_CIR) PLLRDYC:革除PLL就绪中断(1:革除PLL就绪中断标记位PLLRDYF)HSERDYC:革除HSE就绪中断(1:革除HSE就绪中断标记位HSERDYF)HSIRDYC:革除HSI就绪中断(1:革除HSI就绪中断标记位HSIRDYF)LSERDYC:革除LSE就绪中断(1:革除LSE就绪中断标记位LSERDYF)LSIRDYC:革除LSI就绪中断(1:革除LSI就绪中断标记位LSIRDYF)PLLRDYIE:PLL就绪中断使能(1:HSE就绪中断使能)HSIRDYIE:HSI就绪中断使能(1:HSI就绪中断使能)LSERDYIE:LSE就绪中断使能(1:LSE就绪中断使能)LSIRDYIE:LSI就绪中断使能(1:LSI就绪中断使能)PLLRDYF:PLL就绪中断标记(在PLL就绪且PLLRDYIE位被置一时,由硬件置一)HSERDYF:HSE就绪中断标记(在内部低速时钟就绪且HSERDYIE位被置一时,由硬件置一)HSIRDYF:HSI就绪中断标记LSERDYF:LSE就绪中断标记LSIRDYF:LSI就绪中断标记代码示例// 寄存器宏定义// RCC寄存器基地址为0x40021000#define RCC_BASE 0x40021000 // RCC局部寄存器的基地址#define RCC_CR (RCC_BASE + 0x00) // RCC_CR的地址#define RCC_CFGR (RCC_BASE + 0x04)#define FLASH_ACR 0x40022000// 用C语言来拜访寄存器的宏定义#define rRCC_CR (*((volatile unsigned int *)RCC_CR))#define rRCC_CFGR (*((volatile unsigned int *)RCC_CFGR))#define rFLASH_ACR (*((volatile unsigned int *)FLASH_ACR))// 函数作用:时钟源切换到HSE并且使能PLL,将主频设置为72MHzvoid Set_SysClockTo72M(void){ unsigned int rccCrHserdy = 0; unsigned int rccCrPllrdy = 0; unsigned int rccCfrSwsPll = 0; unsigned int faultTime = 0; rRCC_CR = 0x00000083; //复位时钟,设置为初始状态(上电复位用的HSI时钟) //开启内部时钟 rRCC_CR &= ~(1<<16); // 敞开HSEON rRCC_CR |= (1<<16); // 关上HSEON,让HSE工作 do { rccCrHserdy = rRCC_CR & (1<<17); //检测第17位是否为1(检测内部高速时钟是否准备就绪) faultTime++;//超时计数 } while ((faultTime<0x0FFFFFFF) && (rccCrHserdy==0)); //内部时钟开启胜利 if ((rRCC_CR & (1<<17)) != 0) { rFLASH_ACR |= 0x10; rFLASH_ACR &= (~0x03); rFLASH_ACR |= (0x02); // 到这里HSE就准备就绪了,上面再去配PLL并且期待他准备就绪 //复位配置寄存器RCC_CFGR(APB、AHB不分频,时钟切换不可用) rRCC_CFGR &= (~((0x0f<<4) | (0x07<<8) | (0x07<<11))); // AHB和APB2未分频,APB1被2分频,所以最终:AHB和APB2都是72M,APB1是36M rRCC_CFGR |= ((0x00<<4) | (0x04<<8) | (0x00<<11)); rRCC_CFGR &= (~((1<<16) | (1<<17))); // 清零bit17和bit16 rRCC_CFGR |= ((1<<16) | (0<<17)); // 抉择HSE作为PLL输出,HSE不分频 // 设置PLL倍频系数为9 rRCC_CFGR &= (~(0x0f<<18)); // 清零bit18-21 rRCC_CFGR |= (0x07<<18); // 9倍频 // 关上PLL开关 rRCC_CR |= (1<<24); // do while 循环期待PLL时钟稳固 faultTime = 0; do { rccCrPllrdy = rRCC_CR & (1<<25); //检测第25位是否为1 faultTime++;//检测时间 } while ((faultTime<0x0FFFFFFF) && (rccCrPllrdy==0)); if ((rRCC_CR & (1<<25)) == (1<<25)) { // 到这里阐明PLL时钟曾经稳固了,能够用了,上面就能够切了 // 切换PLL输入为SYSCLK rRCC_CFGR &= (~(0x03<<0)); rRCC_CFGR |= (0x02<<0); faultTime = 0; do { rccCfrSwsPll = rRCC_CFGR & (0x03<<2); //检测第25位是否为1 faultTime++;//检测时间 } while ((faultTime<0x0FFFFFFF) && (rccCfrSwsPll!=(0x02<<2))); if ((rRCC_CFGR & (0x03<<2))== (0x02<<2)) { // 到这里咱们的时钟整个就设置好了,能够完结了 } else { // 到这里就阐明PLL输入作为SYSCLK不胜利 while (1); } } else { // 到这里就阐明PLL启动时出错了,PLL不能稳固工作 while (1); } } else { // HSE配置超时,阐明HSE不可用,个别硬件就有问题要去查 while (1); }}

February 3, 2022 · 2 min · jiezi

关于stm:单片机小项目基于51单片机的温度报警器

我的项目性能介绍编程语言:C语言。开发环境:keil。次要性能:1602屏显示工夫和温度,当温度超过预约值时蜂鸣器工作报警。此我的项目只是作为单片机初学者的一个小测验。硬件资源调配1602屏——P0,P2^7,P2^5,P2^6。串口——P2^0,P2^1。传感器——DS18B20 P3^7;DS1302 P3^4,P3^5,P3^6。蜂鸣器——P1^6。LCD1602屏配置在h文件中申明端口和函数: #ifndef __LCD1602_H_#define __LCD1602_H_#include<reg52.h>//重定义关键字#ifndef uchar#define uchar unsigned char#endif#ifndef uint #define uint unsigned int#endif//定义端口#define LCD1602_DATAPINS P0sbit LCD1602_E=P2^7;sbit LCD1602_RW=P2^5;sbit LCD1602_RS=P2^6;//函数申明void Lcd1602_Delay1ms(uint c); //延时函数void LcdWriteCom(uchar com); //写入命令void LcdWriteData(uchar dat); //写入数据void LcdInit(); //LCD初始化子程序#endif在LCD1602.c文件中写入时序和命令等函数代码: #include "LCD1602.h"/***************************延时函数**************************/void Lcd1602_Delay1ms(uint c) //误差 0us{ uchar a,b; for (; c>0; c--) { for (b=199;b>0;b--) { for(a=1;a>0;a--); } } }/***************************底层函数**************************/void LcdWriteCom(uchar com) //写入命令{ LCD1602_E = 0; //使能 LCD1602_RS = 0; //抉择发送命令 LCD1602_RW = 0; //抉择写入 LCD1602_DATAPINS = com; //放入命令 Lcd1602_Delay1ms(1); //期待数据稳固 LCD1602_E = 1; //写入时序 Lcd1602_Delay1ms(5); //放弃工夫 LCD1602_E = 0;}void LcdWriteData(uchar dat) //写入数据{ LCD1602_E = 0; //使能清零 LCD1602_RS = 1; //抉择输出数据 LCD1602_RW = 0; //抉择写入 LCD1602_DATAPINS = dat; //写入数据 Lcd1602_Delay1ms(1); LCD1602_E = 1; //写入时序 Lcd1602_Delay1ms(5); //放弃工夫 LCD1602_E = 0;}void LcdInit() //LCD初始化子程序{ LcdWriteCom(0x38); //开显示 LcdWriteCom(0x0c); //开显示不显示光标 LcdWriteCom(0x06); //写一个指针加1 LcdWriteCom(0x01); //清屏 LcdWriteCom(0x80); //设置数据指针终点}在main.c文件中使用:(这里先让显示屏显示自定义的内容,稍后再做更改) ...

October 20, 2021 · 6 min · jiezi

关于stm:一文讲透Windows内核-x86中断机制详解

搞内核钻研的常常对中断这个概念必定不生疏,常常咱们会接触很多与中断相干的术语,依照软件和硬件进行分类: 硬件CPU相干: IRQIDTcli&sti软件操作系统相干: APCDPCIRQL始终以来对中断这一部分内容弄的只知其一;不知其二,操作系统和CPU之间如何协同工作也是很含糊。最近花了点工夫认真把这块常识进行了梳理,不当之处,还请高手指出,后行谢过了! 本文旨在解答上面这些问题: IRQ和IRQL之间是什么关系?Windows是如何在软件层面上虚构出IRQL这套中断机制的APC和DPC都是软件中断,既然是中断那么对应的IDT表项中的解决例程在哪里呢?0x00 Intel 80386处理器的中断首先,让咱们遗记Windows,从最开始的80386处理器开始,看看Intel设计它的时候是如何解决中断这个货色的。 先来看看这个诞生于1985年的CPU长什么样子:看看那些伸出来的引脚,上面是它的引脚标注图:留神用红圈标注的两个引脚,这两个就是80386处理器为中断留出的两个引脚。其中INTR是可屏蔽中断输出口,NMI是不可屏蔽中断输出口。 那么中断是如何输出给处理器的呢?那么多外部设备,而这只有一个引脚(临时只思考可屏蔽中断),这里就须要为CPU装备一个治理中断的秘书——可编程中断控制器PIC。这个秘书须要干哪些活呢?外部设备的中断都从它来进入中央处理器,所以它负责从外设接管中断信号,并依据优先级向CPU发动中断请求。最开始的这个PIC角色是一个代号为8259A的芯片在进行表演,这货长这样:上面是它的引脚图: 其中IR0-IR7共8个引脚负责连贯外部设备, 8259A PIC的每个IR口都连贯着一条IRQ线,用于接管外设的中断信号。INT负责连贯CPU的INTR引脚,用于向CPU发动中断请求。通常状况下,应用两片8259A芯片进行级联,一片连贯CPU,称为主片,另一片连贯到主PIC的IR2引脚,称为从片,这样总共就能够连贯8+7=15个外设了。如下图所示:在8259A中,默认状况下的优先级是主片IR0的中断请求优先级最高,主片IR7最低,从片IR0-7所有中断请求优先级都相当于IR2。所以IRQ线的优先级由高到低秩序为IRQ0,IRQ1,IRQ8-15,IRQ3-7。这是默认状况,能够通过编程扭转。 在8259a芯片外部有几个重要的寄存器: 中断请求寄存器: IRR,8bit,对应IR0-IR7,当对应引脚产生中断信号时,该bit地位1。 中断服务寄存器: ISR,8bit,对应IR0-IR7,当对应引脚的中断正在被CPU解决时,该bit地位1。 中断屏蔽寄存器: IMR,8bit,对应IR0-IR7,当对应位为1时,示意屏蔽该引脚产生的中断信号。 还有一个中断优先级裁决器: PR,当中断引脚有信号时,联合这次产生中断的IRQ号和ISR中记录的以后正在解决的中断信息,依据优先级来决定是否把这个新的中断信号报告给CPU,以此来产生中断嵌套。 上面是这15条IRQ线别离连贯的外设:当初咱们来看看这个秘书是如何和CPU之间进行协调工作的。 当初假如咱们敲击了一个键盘按键,键盘有中断事件产生,这一事件通过IRQ1这根线告知了主PIC,主PIC通过外部一些判断解决后通过INT发送电信号到CPU侧的INTR。CPU在执行完以后的指令后,查看到INTR有信号,阐明有中断请求来了,再查看eflags中的IF不为零,示意以后容许中断,则发送信号给PIC的-INTA,通知它把本次中断的向量号发送过去。主PIC收到-INTA管脚上的信号后,通过D0-D7引脚,输入此次中断的中断向量号到数据总线(这里简化了交互过程,实际上有两次INTA信号的发送)。CPU拿到这个号后,就能够从IDT中寻找中断服务例程(ISR)进行解决了,前面的事大家都晓得了。 那PIC中的中断向量号是怎么来的呢?各个IRQ是如何对应到IDT中的各个项呢?这里就利用了中断控制器的可编程性来决定的了。 PIC全称为可编程中断控制器,那么它的可编程体现在哪些方面呢?参考资料2《i8259A中断控制器剖析一》一文有比拟具体的形容,大体包含编程指定主从片的IRQ线对应的中断在IDT表中的中断向量号、8259a中断控制器的中断形式、优先级形式、中断嵌套形式,中断屏蔽形式、中断完结形式等等,这些都能够由操作系统编程指定。具体的编程格局在参考资料3《i8259A中断控制器剖析二》一文中有图文介绍。 回到上一个问题,IRQ线上的中断如何和IDT中的条目对应起来,操作系统在初始化的时候,会通过对8259a芯片编程(读写I/O端口),将指定PIC芯片的起始向量号,并要求低三位为0,起始向量号依照8对齐,这样规定的起因是,当中断产生时,低三位将主动填充对应的IRQ号,这样就能够和起始向量号相加间接送给数据总线从而被CPU拿到。具体到Windows中,零碎初始化的时候对PIC的编程为:指定主片的起始中断向量号为0x30,指定从片的起始中断向量号为0x38。这样,通过中断控制器连贯的15个外设将被平坦的映射到IDT中0x30-0x40这一范畴中。Windows内核启动初始化过程中应用了hal!HalpInitializePICs对8259a芯片进行编程,ReactOS中代码如下: 其中0x20,0x21是主片的IO端口,0xa0,0xa1是从片的IO端口:PRIMARY_VECTOR_BASE定义为:具体8259a的编程办法就是读写IO端口,设置对应的管制命令,不必深入研究。咱们来看Windows编程8259a的时候指定了哪些货色。 1、指定了主片的工作形式为级联、中断形式为电信号边际触发2、指定了主片IRQ的中断向量映射基址:0x303、指定了主片的级联形式为应用了本人的IRQ2这个管脚4、指定了主片的工作模式为80x86模式,中断完结形式为一般完结模式5、指定了从片的工作形式为级联、中断形式为电信号边际触发6、指定了从片IRQ的中断向量映射基址:0x387、指定了从片的工作形式级联形式为主片的IRQ2这个管脚8、指定了从片的工作模式为80x86模式,中断完结形式为一般完结模式至此咱们能够晓得,在应用8259A中断控制器的计算机上,通过IRQ线连贯的那15个外设可屏蔽中断是被操作系统线性的映射到了IDT中的一个范畴段。在Windows中是0x30-0x40(PS:在Linux中是0x20-0x2F),同时指定了中断控制器的中断形式为边际触发,完结模式为一般完结模式(也就是须要CPU侧告知中断解决有没有完结并设置对应bit位,不能主动设置)。 0x02 8259a上的Windows IRQL上面来看看IRQL。 从后面咱们看到,硬件层面曾经对中断的解决提供了很好的反对,须要操作系统做的也就两点:首先,初始化的时候对PIC进行编程设置其工作形式并对IRQ进行映射,让这些中断对应到IDT中的各个项,其次,实现这些IDT中的中断服务例程。仿佛这样就够了,那Windows弄出来的一套IRQL又是什么货色呢? 看看《Windows Internals》一书对IRQL的定义:写驱动的时候常常会接触到IRQL这个概念,它实现了Windows里的中断优先级制度,高优先级的中断总是能够优先被解决,而低优先级的中断则不得不期待高优先级中断被解决完后才失去解决。软件虚构进去的这一套机制怎么能管到硬件的优先级呢?这是如何实现的呢? 先来解决两个问题: 1、IRQ和IRQL的关系是什么?、应用KeRaiseIrql晋升以后IRQL后,为什么就能保障不被低优先级的中断打搅?对于第一个问题,在应用8259a中断控制器的计算机中,IRQL=27-IRQ,其就是一个线性关系。 对于第二个问题,《Windows Internals》一书是这样解答的:上面咱们具体来看Windows的实现: IRQL是一个齐全虚构进去的概念,Windows为了实现这一个虚构的机制,齐全虚构了一个中断控制器,它在KPCR中: +0x024 Irql : UChar //IRQL+0x028 IRR : Uint4B //虚构中断请求寄存器+0x02c IrrActive : Uint4B //虚构中断在服务寄存器+0x030 IDR : Uint4B //虚构中断屏蔽寄存器在后面第一局部提到过,通过两片8259a芯片连贯的15个中断源被映射到处理器IDT中的一段范畴,具体Windows而言,是在0x30-0x40这个范畴。这15个IDT中的中断描述符所形容的中断解决例程(ISR)不同于int 3所对应的KiTrap03和int 0e所对应的KiTrap0E,他们的ISR指向的代码位于各自的中断对象KINTERRUPT的DispatchCode。上面是这个构造的定义: typedef struct _KINTERRUPT { CSHORT Type; CSHORT Size; LIST_ENTRY InterruptListEntry; PKSERVICE_ROUTINE ServiceRoutine; PVOID ServiceContext; KSPIN_LOCK SpinLock; ULONG TickCount; PKSPIN_LOCK ActualLock; PVOID DispatchAddress; ULONG Vector; KIRQL Irql; KIRQL SynchronizeIrql; BOOLEAN FloatingSave; BOOLEAN Connected; CHAR Number; UCHAR ShareVector; KINTERRUPT_MODE Mode; ULONG ServiceCount; ULONG DispatchCount; ULONG DispatchCode[106];} KINTERRUPT, *PKINTERRUPT;复制代码 DispatchCode外面的代码是依据一个模板来的,这些ISR解决开始和KiTrap03这些一样,首先会建设陷阱帧,而后会获取本人所在KINTERRUPT对象地址,失去这两个参数之后,便开始应用KiInterruptDispatch或KiChainedDispatch(如果对该中断注册了多个KINTERRUPT构造形成了链表应用此函数)进行中断差遣。而在这两个具体的差遣中都会先调用HalBeginSystemInterrupt,而后才会执行对应中断的理论解决工作,最初会执行HalEndSystemInterrupt实现此次中断解决。上面咱们重点来看看这两个函数。 ...

September 4, 2021 · 1 min · jiezi