当前位置: 首页 > news >正文

05 EXTI外部中断

一、中断系统

  1. 中断系统:管理和执行中断的逻辑结构。
  2. 中断:在主程序运行过程中,出现了特定的中断触发条件——中断源,使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行
    • 中断的作用:极大的提高程序的效率
      比如:
      • 对于外部中断来说,可以是引脚发生了电平跳变;
      • 对于定时器来说,可以是定时的时间到了;
      • 对于串口通信来说,可以是接收到了数据。
  3. 中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源。
    中断优先级就是中断的紧急程度,是我们根据程序设计的需求自己设置的。
    • 中断优先级的作用:为了在多个中断同时申请时判断一下应该先处理哪个。
      如果事件非常紧急,就把优先级设置高一些;如果不是那么紧急,就可以把优先级设置低一些。
      这样可以更好的安排这些中断事件,防止紧急的事件被别的中断耽误。
  4. 中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回。
    • 中断嵌套就是把中断程序再次中断的现象。
    • 中断嵌套是为了照顾非常紧急的中断的,如果现在CPU已经在执行某个中断程序了,这时又发生了一个非常紧急的中断,那这个中断就可以把当前的中断程序进行二次中断,这样新的紧急中断就可以立即被执行了。
    • 能否进行中断嵌套也是由中断优先级来决定的。

中断执行流程

在这里插入图片描述

二、STM32中断

  • 68个可屏蔽中断通道(即中断源),包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设。
  • 使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级。
    在这里插入图片描述
  • 灰色——内核的中断——了解
    • 复位中断:当产生复位事件时,程序就会自动执行复位中断函数,即复位后程序开始执行的位置
    • NMI不可屏蔽中断
    • 硬件失效
    • 存储管理
    • 总线错误
    • 错误应用
    • 等等
  • 白色——STM32外设中断
    • 窗口看门狗:监测程序运行状态的终端
    • PVD电源电压监测:如果供电电压不足,PVD电路就会申请中断
  • 中断的地址:
    • 因为程序中的中断函数的地址是由编译器来分配的,是不固定的,但中断跳转由于硬件的限制,只能跳到固定的地址执行程序。
    • 所以为了能让硬件跳转到一个不固定的中断函数里,就需要在内存中定义一个地址的列表。
    • 这个列表地址是固定的,中断发生后就跳到这个固定位置,然后在这个固定位置由编译器再加上一条跳转到中断函数的代码,这样中断跳转就可以跳到任意位置了。
    • 这个中断地址的列表就叫中断向量表,相当于中断跳转的一个跳板。

1. NVIC

NVIC 嵌套中断向量控制器

  • STM32中用来管理中断、分配优先级的
  • NVIC是一个内核外设,是CPU的小助手
  • NVIC有很多输入口,可以接多个中断线路;NVIC只有一个输出口。
  • 一个外设可能会同时占用多个中断通道,所以有n条线。NVIC根据每个中断的优先级分配中断的先后顺序,之后通过输出口告诉CPU该处理哪个。

(2)NVIC基本结构

在这里插入图片描述

(3)NVIC优先级分组

抢占优先级——可以看作插队
响应优先级——中断嵌套

  • NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级低4-n位的响应优先级

    4位二进制:0到15的数,对应16个优先级
    优先级的数:值越小优先级越高,0就是最高优先级

  • 抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队
    在这里插入图片描述

三、EXTI简介

  • EXTI(Extern Interrupt)外部中断
  • EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
  • 支持的触发方式:上升沿/下降沿/双边沿/软件触发
  • 支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断(PA0和PB0不能同时用)
  • 外部中断占用的通道数(共20个):16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
  • 触发响应方式:中断响应/事件响应

1.EXTI基本结构

在这里插入图片描述
NVIC 中断响应
其他外设 事件响应

2.AFIO复用IO口

  • AFIO主要用于引脚复用功能的选择和重定义
—— 数据选择器的作用
  • 在STM32中,AFIO主要完成两个任务:复用功能引脚重映射、中断引脚选择

    在这里插入图片描述

3.EXTI框图

在这里插入图片描述

或门:多个输入一个输出,任意一个为1,就可以输出1
与门:多个输入一个输出,所有均为1,才可以输出1
非门:一个输入一个输出,输入1就输出0,输入0就输出1
数据选择器:多个输入一个输出

四、旋转编码器简介

  • 旋转编码器:用来测量位置、速度或旋转方向的装置,当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度和方向
  • 类型:机械触点式/霍尔传感器式/光栅式

    在这里插入图片描述

硬件电路

在这里插入图片描述
在这里插入图片描述

五、实操

5.1 对射式红外传感器计次

接线图

在这里插入图片描述

代码实现

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "CountSensor.h"int main(void)
{OLED_Init();CountSensor_Init();OLED_ShowString(1, 1, "Count:");while (1){OLED_ShowNum(1, 7, CountSensor_Get(), 5);}
}

CountSensor.c / .h

#include "stm32f10x.h"                  // Device headeruint16_t CountSensor_Count;/*** @brief 初始化 对射式红外传感器* @param  无* @retval 无*/
void CountSensor_Init(void)
{//1.配置RCC —— 把涉及的外设的时钟都打开RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//2.配置GPIO —— 选择端口为输入模式GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//3.配置AFIOGPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);//4.配置EXTI —— 选择边沿触发方式、触发响应方式EXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line14;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_Init(&EXTI_InitStructure);//5.配置NVIC —— 选择合适优先级NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);//6.通过NVIC外部中断信号进入CPU}/*** @brief 读取对射式红外传感器的当前值* @param  无* @retval CountSensor_Count*/
uint16_t CountSensor_Get(void)
{return CountSensor_Count;
}/*** @brief 中断函数* @param  无* @retval 无*/
void EXTI15_10_IRQHandler(void)
{//1.中断标志位的判断if(EXTI_GetITStatus(EXTI_Line14) == SET){//如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0){CountSensor_Count ++;}//2.清楚中断标志位EXTI_ClearITPendingBit(EXTI_Line14);}
}
#ifndef __COUNT_SENSOR_H
#define __COUNT_SENSOR_Hvoid CountSensor_Init(void);
uint16_t CountSensor_Get(void);#endif

程序现象

  • 程序启动时,OLED屏幕上会显示"Count:"字符串
  • 之后,每挡一次传感器,计数就会+1,并将这个数据更新显示在OLED屏幕的指定位置。
  • 如果EXTI_Trigger配置为下降沿触发EXTI_Trigger_Falling,在移开挡光片时触发中断,计数+1
  • 如果EXTI_Trigger配置为上升沿触发EXTI_Trigger_Rising,在遮挡时触发中断,计数+1
  • 如果EXTI_Trigger配置为双边沿触发EXTI_Trigger_Rising_Falling,在遮挡和移开挡光片时均触发中断,计数+1

5.2 旋转编码器计次

接线图

在这里插入图片描述

代码实现

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Encoder.h"int16_t Num;int main(void)
{OLED_Init();Encoder_Init();OLED_ShowString(1, 1, "Num:");while (1){Num += Encoder_Get();	//Encoder_Get函数返回的是调用该函数的间隔里,旋转编码器产生的正负脉冲数,所以返回值直接+=给NumOLED_ShowNum(1, 5, Num, 5);}
}

Encoder.c / .h

#include "stm32f10x.h"                  // Device headerint16_t Encoder_Count;void Encoder_Init(void)
{//1.配置RCC —— 把涉及的外设的时钟都打开RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//2.配置GPIO —— 选择端口为输入模式GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//3.配置AFIOGPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);//4.配置EXTI —— 选择边沿触发方式、触发响应方式EXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_Init(&EXTI_InitStructure);//5.配置NVIC —— 选择合适优先级NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;NVIC_Init(&NVIC_InitStructure);//6.通过NVIC外部中断信号进入CPU}int16_t Encoder_Get(void)
{int16_t Temp;Temp = Encoder_Count;Encoder_Count = 0;return Temp;
}void EXTI0_IRQHandler(void)
{//1.中断标志位的判断if(EXTI_GetITStatus(EXTI_Line0) == SET){//如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0){if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0){Encoder_Count --;}}//2.清楚中断标志位EXTI_ClearITPendingBit(EXTI_Line0);}
}void EXTI1_IRQHandler(void)
{//1.中断标志位的判断if(EXTI_GetITStatus(EXTI_Line1) == SET){//如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0){if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0){Encoder_Count --;}}//2.清楚中断标志位EXTI_ClearITPendingBit(EXTI_Line1);}
}
#ifndef __ENCODER_H
#define __ENCODER_Hvoid Encoder_Init(void);
int16_t Encoder_Get(void);#endif

程序现象

  • 程序启动时,OLED屏幕上会显示"Num:"字符串
  • 向右转,数字增加;向左转,数字减小。

相关文章:

05 EXTI外部中断

一、中断系统 中断系统:管理和执行中断的逻辑结构。中断:在主程序运行过程中,出现了特定的中断触发条件——中断源,使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继…...

2024.2.23

1.1.1 信号默认、捕获、忽略处理(普通信号) #include <myhead.h> void handler(int signo) {if(signoSIGINT){printf("用户键入 ctrlc\n");} } int main(int argc, const char *argv[]) {//忽略信号if(signal(SIGINT,SIG_IGN)SIG_ERR){perror("signal er…...

PHP实现分离金额和其他内容便于统计计算

得到的结果可以粘贴到excel计算 <?php if($_GET["x"] "cha"){ $tips isset($_POST[tips]) ? $_POST[tips] : ; $pattern /(\d\.\d|\d)/; $result preg_replace($pattern, "\t\${1}\t", $tips); echo "<h2><strong>数…...

基础数据结构和算法《》

递归 1.递归应该一种比较常见的实现一些特殊代码逻辑时需要做的&#xff0c;但常常也是最绕的一种方式&#xff0c;在解释递归 之前&#xff0c;我们用循环和递归来做个比较1.1.如果你打开一扇门后&#xff0c;同样发现前方也有一扇们&#xff0c;紧接着你又打开下一扇门...直…...

[设计模式Java实现附plantuml源码~行为型]对象间的联动~观察者模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…...

vue3+js 实现记住密码功能

常见的几种实现方式 1 基于spring security 的remember me 功能 ​​​​​​​ localStorage 除非主动清除localStorage 里的信息 &#xff0c;不然永远存在&#xff0c;关闭浏览器之后下次启动仍然存在 存放数据大小一般为5M 不与服务器进行交互通信 cookies 可以…...

基于单片机的太阳能电池板自动跟踪系统的研究

摘要 伴随着人类社会的发展,人口基数越来越大,电量消耗巨大,传统发电原 料污染环境的同时,可用量日益减少,给人类未来生产生活带来了一定的威胁, 因而解决日益剧增的用电量,寻求一种新能源显得极其重要。论文正是基于此 背景下,针对当前太阳能电池板采光率低、自动化水…...

React 模态框的设计(二)

自定义组件是每个前端开发者必备的技能。我们在使用现有框架时难免有一些超乎框架以处的特别的需求&#xff0c;比如关于弹窗&#xff0c;每个应用都会用到&#xff0c;但是有时我们使用的框架中提供的弹窗功能也是功能有限&#xff0c;无法满足我们的应用需求&#xff0c;今天…...

操作符详解3

✨✨ 欢迎大家来到莉莉的博文✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 前面我们已经讲过算术操作符、赋值操作符、逻辑操作符、条件操作符和部分的单目操作 符&#xff0c;今天继续介绍一部分。 目录 1.操作符的分类 2…...

【C语言基础】:操作符详解(一)

文章目录 操作符详解1. 操作符的分类2. 二进制和进制转换2.1 什么是二进制、八进制、十进制、十六进制2.1.1 二进制和进制转换2.1.2 二进制转十进制2.2.3 二进制转八进制2.2.4 二进制转十六进制 3. 源码、反码、补码4. 移位操作符4.1 左移操作符4.2 右移操作符 5. 位操作符&…...

通俗易懂分析:Vite和Webpack的区别

1、对项目构建的理解 先从浏览器出发&#xff0c; 浏览器是由浏览器内核和JS引擎组成&#xff1b;浏览器内核编译解析html代码和css代码&#xff0c;js引擎编译解析JavaScript代码&#xff1b;所以从本质上&#xff0c;浏览器只能识别运行JavaScript、CSS、HTML代码。 而我们在…...

OpenCart程序结构与业务逻辑

一、程序业务逻辑说明 在 OpenCart 中&#xff0c;index.php 文件是整个应用程序的入口文件&#xff0c;它负责初始化应用程序并调度请求。以下是 index.php 文件加载执行的流程&#xff1a; 1. **设置路径常量&#xff1a;** - index.php 首先定义了一些重要的路径常量&…...

软件License授权原理

软件License授权原理 你知道License是如何防止别人破解的吗?本文将介绍License的生成原理,理解了License的授权原理你不但可以防止别人破解你的License,你甚至可以研究别人的License找到它们的漏洞。喜欢本文的朋友建议收藏+关注,方便以后复习查阅。 什么是License? 在…...

C/C++实现老鼠走迷宫

老鼠形象可以辨认&#xff0c;可以用上下左右操纵老鼠;正确检测结果&#xff0c;若老鼠在规定的时间内走到粮仓&#xff0c;提示成功&#xff0c;否则提示失败。代码分为3个文件&#xff1a;main.cpp、play.h、play.cpp。 main.cpp: #include <iostream> #include <…...

[Linux]文件基础-如何管理文件

回顾C语言之 - 文件如何被写入 fopen fwrite fread fclose fseek … 这一系列函数都是C语言中对文件进行的操作&#xff1a; int main() {FILE* fpfopen("text","w");char str[20]"write into text";fputs(str,fp);fclose(fp);return 0; }而上…...

bat 查找文件所在

脚本 在批处理文件&#xff08;.bat&#xff09;中查找文件所在的目录&#xff0c;你可以使用dir命令结合循环和条件语句来实现。以下是一个简单的示例&#xff0c;演示如何在批处理文件中查找指定文件并输出其所在目录&#xff1a; echo off setlocal enabledelayedexpansio…...

程序员的守护神:为何电脑永不熄灭?

在这个信息时代&#xff0c;程序员成了推动社会进步的“隐形英雄”。他们通宵达旦&#xff0c;手指在键盘上跳跃&#xff0c;创造出一个个令人惊叹的数字世界。有趣的是&#xff0c;你可能注意到了一个现象&#xff1a;程序员似乎总是不关电脑。这并非他们对电脑上瘾&#xff0…...

Kafka快速实战以及基本原理详解

Kafka快速实战以及基本原理详解 基本概念 Kafka是一个分布式、支持分区、多副本&#xff0c;基于ZK的分布式消息系统&#xff0c;最大的特性就是可以实时的处理大量数据以满足各种需求场景&#xff0c;比如Hadoop的批处理系统、低延迟的实时系统、Storm/Spark流式处理引擎、日…...

微信小程序(4)- 事件系统和模板语法

1. 事件系统 1.1 事件绑定和事件对象 小程序中绑定事件与在网页开发中绑定事件几乎一致&#xff0c;只不过在小程序不能通过 on 的方式绑定事件&#xff0c;也没有 click 等事件&#xff0c;小程序中绑定事件使用 bind 方法&#xff0c;click 事件也需要使用 tap 事件来进行代…...

【Java多线程】对线程池的理解并模拟实现线程池

目录 1、池 1.1、线程池 2、ThreadPoolExecutor 线程池类 3、Executors 工厂类 4、模拟实现线程池 1、池 “池”这个概念见到非常多&#xff0c;例如常量池、数据库连接池、线程池、进程池、内存池。 所谓“池”的概念就是&#xff1a;&#xff08;提高效率&#xff09; 1…...

python连接mysql数据库

连接MySQL数据库&#xff0c;通常我们会使用Python的mysql-connector-python库。下面是一个基本的示例来展示如何使用Python连接到MySQL数据库。 首先&#xff0c;确保你已经安装了mysql-connector-python库。如果没有&#xff0c;你可以使用pip来安装它&#xff1a; pip ins…...

docker用法

首先需要去docker官网注册你的账号&#xff0c;记住账号名称和密码&#xff1b; 然后在本地执行&#xff1a; docker login登录OK。 把ubuntu下载到本地&#xff1a; sudo docker pull ubuntusudo docker images输出&#xff1a; REPOSITORY TAG …...

DIcom调试Planar configuration

最近和CBCT组同事调dicom图像 这边得图像模块老不兼容对方得dicom文件。 vtk兼容&#xff0c;自己写得原生解析不兼容。 给对方调好了格式&#xff0c;下次生成文件还会有错。 简单记录下&#xff0c;日后备查。 今天对方又加了 个字段&#xff1a;Planar configuration 查…...

C#与VisionPro联合开发——跳转页面

1、跳转页面并打开相机 From1 所有代码展示 using System; using System.IO; using System.Windows.Forms; //引入VisionPro命名空间 using Cognex.VisionPro;namespace ConnectCamera {public partial class Form1 : Form {public Form1() {InitializeComponent();}CogAcqFif…...

服务端测试开发必备技能:Mock测试

什么是mock测试 Mock 测试就是在测试活动中&#xff0c;对于某些不容易构造或者不容易获取的数据/场景&#xff0c;用一个Mock对象来创建以便测试的测试方法。 Mock测试常见场景 无法控制第三方系统接口的返回&#xff0c;返回的数据不满足要求依赖的接口还未开发完成&#…...

vue3中ref创建变量取值时自动补充 .value 插件 volar

插件 TypeScript Vue Plugin (Volar) 设置中配置...

clickhouse的docker部署与springboot整合

注意:镜像bitnami/clickhouse包含服务端和客户端,yandex版本需要使用yandex/clickhouse-server,yandex/clickhouse-server docker启动命令(允许空密码 -e ALLOW_EMPTY_PASSWORD=yes),clickhouse版本不同,配置文件在的位置也会不一样/etc/clickhouse-server/config.xml d…...

Node.js_基础知识(计算机硬件基础)

主机的基本组成 CPU:Central Processing Unit,即中央处理器,是计算机的核心部件。是一块集成电路芯片,能够执行计算机指令并控制计算机的各种操作,负责运算和处理数据内存:是电脑硬件中的一块电路板,用于暂时存储CPU中的运算数据,是计算机与CPU进行沟通的桥梁,负责存储…...

git bash :download.sh: line 1: wget: command not found(已解决)

Windows中git bash完全可以替代原生的cmd&#xff0c;但是对于git bash会有一些Linux下广泛使用的命令的缺失&#xff0c;比如wget命令。 1、下载wget.exe&#xff0c;地址&#xff1a;https://eternallybored.org/misc/wget/ 2、将wget.exe 拷贝到C:\Program Files\Git\ming…...

BlackberryQ10 是可以安装 Android 4.3 应用的,Web UserAgent 版本信息

BlackberryQ10 是可以安装 Android 4.3 应用的 最近淘了个 Q10 手机&#xff0c;非常稀罕它&#xff0c;拿着手感一流。这么好的东西&#xff0c;就想给它装点东西&#xff0c;但目前所有的应用都已经抛弃这个安卓版本了。 一、开发环境介绍 BlackBerry Q10 的 安卓版本是 4.…...