8修改host_正点原子【STM32-F407探索者】第五十九章 USB 鼠标键盘(Host)实验

1)资料下载:点击资料即可下载

2)对正点原子Linux感兴趣的同学可以加群讨论:935446741

3)关注正点原子公众号,获取最新资料更新

1451daa71c1a28c4e968abe6ece7c8ed.png

上一章我们向大家介绍了如何利用 STM32F4 的 USB HOST 接口来驱动 U 盘,本章,我们

将利用 STM32F4 的 USB HOST 来驱动 USB 鼠标/键盘。本章分为如下几个部分:

59.1 USB 鼠标键盘简介

59.2 硬件设计

59.3 软件设计

59.4 下载验证

59.1 USB 鼠标键盘简介

传统的鼠标和键盘是采用 PS/2 接口和电脑通信的,但是现在 PS/2 接口在电脑上逐渐消失,

所以现在越来越多的鼠标键盘采用的是 USB 接口,而不是 PS/2 接口的了。

USB 鼠标键盘属于 USB HID 设备。USB HID 即:Human Interface Device(人机交互设备)

的缩写,键盘、鼠标与游戏杆等都属于此类设备。不过 HID 设备并不一定要有人机接口,只要

符合 HID 类别规范的设备都是 HID 设备。关于 USB HID 的知识,我们这里就不详细介绍了,

请大家自行百度学习。

本章,我们同上一章一样,我们直接移植官方的 USB HID 例程,官方例程路径:光盘→8,

STM32 参考资料→STM32 USB 学习资料→STM32_USB-Host-Device_Lib_V2.1.0→Project→

USB_Host_Examples→HID,该例程支持 USB 鼠标和键盘等 USB HID 设备,本章我们将移植这

个例程到探索者 STM32F407 开发板上。

59.2 硬件设计

本节实验功能简介:开机的时候先显示一些提示信息,然后初始化 USB HOST,并不断轮

询。当检测到 USB 鼠标/键盘的插入后,显示设备类型,并显示设备输入数据,

如果是 USB 鼠标:将显示鼠标移动的坐标(X,Y 坐标),滚轮滚动数值(Z 坐标)以及

按键(左中右)。

如果是 USB 键盘:将显示键盘输入的数字/字母等内容(不是所有按键都支持,部分按键

没有做解码支持,比如 F1~F12)。

最后,还是用 DS0 提示程序正在运行。

所要用到的硬件资源如下:

1) 指示灯 DS0

2) 串口

3) TFTLCD 模块

4) USB HOST 接口

这几个部分,在之前的实例中都已经介绍过了,我们在此就不多说了。这里再次提醒大家,

P11 的连接,要通过跳线帽连接 PA11 和 D-以及 PA12 和 D+。

59.3 软件设计

本章,我们在第十八章实验 (实验 13 TFTLCD 显示实验 )的基础上修改,先打开实验

13 的工程,在 HARDWARE 文件夹所在文件夹下新建一个 USB 的文件夹,对照官方 HID 例子,

将相关文件拷贝到 USB 文件夹下。

然后,我们在工程里面添加 USB HID 相关代码,最终得到如图 59.3.1 所示的工程:

8f08deada110f62a75036e3e7dd33027.png
图 59.3.1 USB 鼠标键盘工程截图

可以看到,USB 部分代码,同上一章的在结构上是一模一样的,只是.c 文件稍微有些变化。

同样,我们移植需要修改的代码,就是 USB_APP 里面的这两个.c 文件了。

其中 usb_bsp.c 的代码,和之前的章节一模一样,可以用上一章的代码直接替换即可正常使

用。

usbh_usr.c 里面的代码,则有所变化,重点代码如下:

//下面两个函数,为 ALIENTEK 添加,以防止 USB 死机

//USB 枚举状态死机检测,防止 USB 枚举失败导致的死机

//phost:USB_HOST 结构体指针

//返回值:0,没有死机

// 1,死机了,外部必须重新启动 USB 连接.

u8 USBH_Check_EnumeDead(USBH_HOST *phost)

{

static u16 errcnt=0;

//这个状态,如果持续存在,则说明 USB 死机了.

if(phost->gState==HOST_CTRL_XFER&&(phost->EnumState==ENUM_IDLE||

phost->EnumState==ENUM_GET_FULL_DEV_DESC))

{

errcnt++;

if(errcnt>2000)//死机了

{

errcnt=0;

RCC->AHB2RSTR|=1<<7; //USB OTG FS 复位

delay_ms(5);

RCC->AHB2RSTR&=~(1<<7); //复位结束

return 1;

}

}else errcnt=0;

return 0;

}

//USB HID 通信死机检测,防止 USB 通信死机(暂时仅针对:DTERR,即 Data toggle error)

//pcore:USB_OTG_Core_dev_HANDLE 结构体指针

//phidm:HID_Machine_TypeDef 结构体指针

//返回值:0,没有死机

// 1,死机了,外部必须重新启动 USB 连接.

u8 USBH_Check_HIDCommDead(USB_OTG_CORE_HANDLE *pcore,

HID_Machine_TypeDef *phidm)

{

if(pcore->host.HC_Status[phidm->hc_num_in]==HC_DATATGLERR)

//检测到 DTERR 错误,直接重启 USB.

{

return 1;

}

return 0;

}

//

//USB 键盘鼠标数据处理

//鼠标初始化

void USR_MOUSE_Init(void)

{

USBH_Msg_Show(2);

//USB 鼠标

USB_FIRST_PLUGIN_FLAG=1;//标记第一次插入

}

//键盘初始化

void USR_KEYBRD_Init(void)

{

USBH_Msg_Show(1);

//USB 键盘

USB_FIRST_PLUGIN_FLAG=1;//标记第一次插入

}

//零时数组,用于存放鼠标坐标/键盘输入内容(4.3 屏,最大可以输入 2016 字节)

__align(4) u8 tbuf[2017];

//USB 鼠标数据处理

//data:USB 鼠标数据结构体指针

void USR_MOUSE_ProcessData(HID_MOUSE_Data_TypeDef *data)

{

static signed short x,y,z;

if(USB_FIRST_PLUGIN_FLAG)//第一次插入,将数据清零

{

USB_FIRST_PLUGIN_FLAG=0;

x=y=z=0;

}

x+=(signed char)data->x;

if(x>9999)x=9999;

if(x<-9999)x=-9999;

y+=(signed char)data->y;

if(y>9999)y=9999;

if(y<-9999)y=-9999;

z+=(signed char)data->z;

if(z>9999)z=9999;

if(z<-9999)z=-9999;

POINT_COLOR=BLUE;

sprintf((char*)tbuf,"BUTTON:");

if(data->button&0X01)strcat((char*)tbuf,"LEFT ");

if((data->button&0X03)==0X02)strcat((char*)tbuf,"RIGHT");

else if((data->button&0X03)==0X03)strcat((char*)tbuf,"+RIGHT");

if((data->button&0X07)==0X04)strcat((char*)tbuf,"MID ");

else if((data->button&0X07)>0X04)strcat((char*)tbuf,"+MID");

LCD_Fill(30+56,180,lcddev.width-1,180+16,WHITE);

LCD_ShowString(30,180,210,16,16,tbuf);

sprintf((char*)tbuf,"X POS:%05d",x);

LCD_ShowString(30,200,200,16,16,tbuf);

sprintf((char*)tbuf,"Y POS:%05d",y);

LCD_ShowString(30,220,200,16,16,tbuf);

sprintf((char*)tbuf,"Z POS:%05d",z);

LCD_ShowString(30,240,200,16,16,tbuf);

//printf("btn,X,Y,Z:0x%x,%d,%d,%drn",data->button,(signed char)data->x,

//(signed char)data->y,(signed char)data->z);

}

//USB 键盘数据处理

//data:USB 鼠标数据结构体指针

void USR_KEYBRD_ProcessData (uint8_t data)

{

static u16 pos;

static u16 endx,endy;

static u16 maxinputchar;

u8 buf[4];

if(USB_FIRST_PLUGIN_FLAG)//第一次插入,将数据清零

{

USB_FIRST_PLUGIN_FLAG=0;

endx=((lcddev.width-30)/8)*8+30;

//得到 endx 值

endy=((lcddev.height-220)/16)*16+220;

//得到 endy 值

maxinputchar=((lcddev.width-30)/8);

maxinputchar*=(lcddev.height-220)/16;//当前 LCD 最大可以显示的字符数.

pos=0;

}

POINT_COLOR=BLUE;

sprintf((char*)buf,"%02X",data);

LCD_ShowString(30+56,180,200,16,16,buf);//显示键值

if(data>=' '&&data<='~')

{

tbuf[pos++]=data;

tbuf[pos]=0;

//添加结束符.

if(pos>maxinputchar)pos=maxinputchar;//最大输入这么多

}else if(data==0X0D) //退格键

{

if(pos)pos--;

tbuf[pos]=0;

//添加结束符.

}

if(pos<=maxinputchar) //没有超过显示区

{

LCD_Fill(30,220,endx,endy,WHITE);

LCD_ShowString(30,220,endx-30,endy-220,16,tbuf);

}

//printf("KEY Board Value:%02Xrn",data);

//printf("KEY Board Char:%crn",data);

}

ST 官方的 USB HID 例程,仅仅是能用,很多地方还要改善,比如识别率低,容易死机(枚

举/通信都可能死机)等问题,这里:USBH_Check_EnumeDead 和 USBH_Check_HIDCommDead

这两个函数,就是我们针对官方 HID 例程现有 bug 做出的改进处理,通过这两个函数,可以检

测枚举/通信是否正常,当出现异常时,直接重启 USB 内核,重新连接设备,这样可以防止死

机造成的程序无响应情况。

另外,为了提高对鼠标键盘的识别率和兼容性,对 usbh_hid_core.c 里面的两处代码进行了

修改:

1,USBH_HID_ClassRequest 函数,修改代码(351 行)为:

classReqStatus = USBH_Set_Idle (pdev, pphost, 100, 0);//这里 duration 官方设置的是 0,修改为

//100,提高兼容性

2,USBH_Set_Idle 函数,修改代码(542 行)为:

phost->Control.setup.b.wLength.w = 100; //官方的这里设置的是 0,导致部分鼠标无法识别,

//这里修改为 100 以后,识别率明显提高.

以上两处地方,官方默认值都是设置的 0,我们修改为 100 后,可以明显提高 USB 鼠标/

键盘的识别率,兼容性好很多。

还有,在 usbh_hid_keybd.h 里面,要修改键盘类型的定义,改为:

#define QWERTY_KEYBOARD

//通用键盘

//#define AZERTY_KEYBOARD

//法国版键盘

ST 官方例程,是使用的法国版键盘,一般我们国内用的是通用键盘,所以,需要换一个宏

定义(换成:QWERTY_KEYBOARD)。

最后,在 usbh_hid_mouse.c 里面,MOUSE_Decode 函数用于鼠标数据解析,但是 ST 官方

例程仅对 4 字节鼠标数据做了解析,而忽略了 5 字节/6 字节鼠标数据的处理,所以,需要修改

该函数为:

extern HID_Machine_TypeDef HID_Machine;

static void MOUSE_Decode(uint8_t *data)

{

if(HID_Machine.length==5||HID_Machine.length==6)//5/6 字节长度 USB 鼠标数据处理

{

HID_MOUSE_Data.button = data[0];

HID_MOUSE_Data.x = data[1];

HID_MOUSE_Data.y = data[3]<<4|data[2]>>4;

HID_MOUSE_Data.z = data[4];

}else if(HID_Machine.length==4) //4 字节长度的 USB 鼠标数据处理

{

HID_MOUSE_Data.button = data[0];

HID_MOUSE_Data.x = data[1];

HID_MOUSE_Data.y = data[2];

HID_MOUSE_Data.z = data[3];

}

USR_MOUSE_ProcessData(&HID_MOUSE_Data);

}

再回到 usbh_usr.c,USR_MOUSE_Init 和 USR_MOUSE_ProcessData 用于处理鼠标数据,这

两个函数在 usbh_hid_mouse.c 里面被调用,USR_MOUSE_Init 在鼠标初始化的时候被调用,而

USR_MOUSE_ProcessData 函数,则在鼠标初始化成功,轮询数据的时候调用,处理鼠标数据,

该函数将得到的鼠标数据显示在 LCD 上面。

同样,USR_KEYBRD_Init 和 USR_KEYBRD_ProcessData 用于处理键盘数据,这两个函数

在 usbh_hid_keybd.c 里面被调用,USR_KEYBRD_Init 在键盘初始化的时候被调用,而

USR_KEYBRD_ProcessData 函数,则在键盘初始化成功,轮询数据的时候调用,处理键盘数据,

该函数将键盘输入的字符显示在 LCD 上面。

其他代码,我们就不再介绍了,请大家参考开发板光盘本例程源码。

最后,来看看 main.c 里面的代码,如下:

USBH_HOST USB_Host;

USB_OTG_CORE_HANDLE USB_OTG_Core_dev;

extern HID_Machine_TypeDef HID_Machine;

//USB 信息显示

//msgx:0,USB 无连接

// 1,USB 键盘

// 2,USB 鼠标

// 3,不支持的 USB 设备

void USBH_Msg_Show(u8 msgx)

{

POINT_COLOR=RED;

switch(msgx)

{

case 0: //USB 无连接

LCD_ShowString(30,130,200,16,16,"USB Connecting...");

LCD_Fill(0,150,lcddev.width,lcddev.height,WHITE);

break;

case 1: //USB 键盘

LCD_ShowString(30,130,200,16,16,"USB Connected ");

LCD_ShowString(30,150,200,16,16,"USB KeyBoard");

LCD_ShowString(30,180,210,16,16,"KEYVAL:");

LCD_ShowString(30,200,210,16,16,"INPUT STRING:");

break;

case 2: //USB 鼠标

LCD_ShowString(30,130,200,16,16,"USB Connected ");

LCD_ShowString(30,150,200,16,16,"USB Mouse");

LCD_ShowString(30,180,210,16,16,"BUTTON:");

LCD_ShowString(30,200,210,16,16,"X POS:");

LCD_ShowString(30,220,210,16,16,"Y POS:");

LCD_ShowString(30,240,210,16,16,"Z POS:");

break;

case 3: //不支持的 USB 设备

LCD_ShowString(30,130,200,16,16,"USB Connected ");

LCD_ShowString(30,150,200,16,16,"Unknow Device");

break;

}

}

//HID 重新连接

void USBH_HID_Reconnect(void)

{

//关闭之前的连接

USBH_DeInit(&USB_OTG_Core_dev,&USB_Host); //复位 USB HOST

USB_OTG_StopHost(&USB_OTG_Core_dev);

//停止 USBhost

if(USB_Host.usr_cb->DeviceDisconnected)

//存在,才禁止

{

USB_Host.usr_cb->DeviceDisconnected(); //关闭 USB 连接

USBH_DeInit(&USB_OTG_Core_dev, &USB_Host);

USB_Host.usr_cb->DeInit();

USB_Host.class_cb->DeInit(&USB_OTG_Core_dev,&USB_Host.device_prop);

}

USB_OTG_DisableGlobalInt(&USB_OTG_Core_dev);//关闭所有中断

//重新复位 USB

__HAL_RCC_USB_OTG_FS_FORCE_RESET();//USB OTG FS 复位

delay_ms(5);

__HAL_RCC_USB_OTG_FS_RELEASE_RESET();//复位结束

memset(&USB_OTG_Core_dev,0,sizeof(USB_OTG_CORE_HANDLE));

memset(&USB_Host,0,sizeof(USB_Host));

//重新连接 USB HID 设备

USBH_Init(&USB_OTG_Core_dev,USB_OTG_FS_CORE_ID,&USB_Host,&HID_cb,

&USR_Callbacks);

}

int main(void)

{

u32 t;

HAL_Init();

//初始化 HAL 库

Stm32_Clock_Init(336,8,2,7);

//设置时钟,168Mhz

delay_init(168);

//初始化延时函数

uart_init(115200);

//初始化 USART

usmart_dev.init(84);

//初始化 USMART

LED_Init();

//初始化 LED

KEY_Init();

//初始化 KEY

LCD_Init(); //初始化 LCD

SRAM_Init();

//初始化外部 SRAM

W25QXX_Init();

//初始化 W25Q128

POINT_COLOR=RED;

LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");

LCD_ShowString(30,70,200,16,16,"USB MOUSE/KEYBOARD TEST");

LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");

LCD_ShowString(30,110,200,16,16,"2017/5/16");

LCD_ShowString(30,130,200,16,16,"USB Connecting...");

//初始化 USB 主机

USBH_Init(&USB_OTG_Core_dev,USB_OTG_FS_CORE_ID,&USB_Host,&HID_cb,

&USR_Callbacks);

while(1)

{

USBH_Process(&USB_OTG_Core_dev, &USB_Host);

if(bDeviceState==1)//连接建立了

{

if(USBH_Check_HIDCommDead(&USB_OTG_Core_dev,&HID_Machine))

//检测 USB HID 通信,是否还正常?

{

USBH_HID_Reconnect();//重连

}

}else

//连接未建立的时候,检测

{

if(USBH_Check_EnumeDead(&USB_Host))

//检测 USB HOST 枚举是否死机了?死机了,则重新初始化

{

USBH_HID_Reconnect();//重连

}

}

t++;

if(t==200000)

{

LED0=!LED0;

t=0;

}

}

}

这里总共三个函数:USBH_Msg_Show 用于显示一些提示信息,在 usbh_usr.c 里面被相关

函数调用。USBH_HID_Reconnect 则用于 USB HID 重新连接,当发现枚举/通信死机的时候,

调用该函数实现 USB 复位重启,以重新连接;最后,main 函数就比较简单了,处理方式和上

一章几乎一样,只是多了一些通信死机处理。

软件设计部分就为大家介绍到这里。

59.4 下载验证

在代码编译成功之后,我们下载到探索者 STM32F4 开发板上,然后在 USB_HOST 端子插

入 USB 鼠标/键盘,注意:此时 USB SLAVE 口不要插 USB 线到电脑,否则会干扰!!

等 USB 鼠标/键盘成功识别后,便可以看到 LCD 显示 USB Connected,并显示设备类型:

USB Mouse 或者 USB KeyBoard,同时也会显示输入的数据,如图 58.4.1 和图 58.4.2 所示:

4b748a481ae1b5af10496f1fbaa42674.png
图 59.4.1 USB 鼠标测试

f4d9b6c9cbdde5598afbf235f03a440b.png
图 59.4.2 USB 键盘测试

其中,图 59.4.1 是 USB 鼠标测试界面,图 59.4.2 是 USB 键盘测试界面。

最后,特别提醒大家,由于例程的 HID 内核,只处理了第一个接口描述符,所以对于 USB

符合设备,只能识别第一个描述符所代表的设备。体现到实际使用中,就是:USB 无线鼠标,

一般是无法使用(被识别为键盘),而 USB 无线键盘,可以使用,因为键盘在第一个描述符,

鼠标在第二个描述符。

如果想支持 USB 无线鼠标,可以通过修改 usbh_hid_core.c 里面的 USBH_HID_InterfaceInit

函数来支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/397204.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CF815C Karen and Supermarket [树形DP]

题目传送门 Karen and Supermarket On the way home, Karen decided to stop by the supermarket to buy some groceries. She needs to buy a lot of goods, but since she is a student her budget is still quite limited. In fact, she can only spend up to b dollars. Th…

6工程文件夹作用_data_dragon数据工程小工具收集

最近在GitHub上创建了一个新工程&#xff0c;收集个人在数据工程工作的小工具集合&#xff0c;命名为data_dragon (数据一条龙)。取这个名字的是希望这些脚本或代码能够复用&#xff0c;端到端地减少临时数据处理的时间。最近因为工作上的一些变化&#xff0c;写作节奏有点被打…

暑假第十七测

题解&#xff1a; 第一题 #include<bits/stdc.h> using namespace std; #define ll long long const int M 1e5 10; ll a[M], b[M], ans; priority_queue <ll, vector<ll> , greater<ll> > Q; int main(){freopen("buy.in","r",…

Nginx搭建flv视频点播服务器

Nginx搭建flv视频点播服务器前一段时间使用Nginx搭建的多媒体服务器只能在缓冲过的时间区域内拖放, 而不能拖放到未缓冲的地方. 这就带来了一个问题: 如果视频限速的速率很小, 那么客户端观看视频时肯定不流畅, 而且用户不能向前拖放, 用户体验很不好. 如果视频限速的速率很大或…

编码拾遗

1 #!/usr/bin/env python32 #-*- coding:utf-8 -*-3 4 Administrator 5 2018/8/16 6 7 8 # fopen("demo","r",encoding"utf8")9 # dataf.read() 10 # print(data) 11 # f.close() 12 13 14 # print("沈哲子") 15 16 s"中国&qu…

mybatis 不生效 参数_Mybatis-日志配置

日志Mybatis 的内置日志工厂提供日志功能&#xff0c;内置日志工厂将日志交给以下其中一种工具作代理&#xff1a;SLF4JApache Commons LoggingLog4j 2Log4jJDK loggingMyBatis 内置日志工厂基于运行时自省机制选择合适的日志工具。它会使用第一个查找得到的工具(按上文列举的顺…

PS通过滤色实现简单的图片拼合

素材如下&#xff1a; 素材一&#xff1a; 雪山 素材二&#xff1a; 月亮 效果&#xff1a; 实现步骤 1、在PS中打开雪山素材一 2、将月亮素材直接拖入雪山所在的图层中 3、锁定置入素材的高宽比&#xff08;点击一下链状按钮&#xff09; 4、调整月亮到合适大小合适位置 5、…

预处理:主成分分析与白化

主成分分析 引言 主成分分析&#xff08;PCA&#xff09;是一种能够极大提升无监督特征学习速度的数据降维算法。更重要的是&#xff0c;理解PCA算法&#xff0c;对实现白化算法有很大的帮助&#xff0c;很多算法都先用白化算法作预处理步骤。 假设你使用图像来训练算法&#x…

swagger 修改dto注解_Web服务开发:Spring集成Swagger,3步自动生成API文档

目录&#xff1a;1&#xff0c;Spring Boot集成Swagger2&#xff0c;Swagger接口文档页面3&#xff0c;常见问题和解决方法在Sping开发REST接口服务时&#xff0c;API文档是不可缺少的一个重要部分。Swagger框架定义了完整的REST接口文档规范&#xff0c;提供了强大的页面测试功…

WPF自定义控件之列表滑动特效 PowerListBox

列表控件是应用程序中常见的控件之一&#xff0c;对其做一些绚丽的视觉特效&#xff0c;可以让软件增色不少。 本人网上看过一个视频&#xff0c;是windows phone 7系统上的一个App的列表滚动效果&#xff0c;效果非常炫 现在在WPF上用ListBox重现此效果 首先我们来分析一下&am…

CnosDB如何确保多步操作的最终一致性?

背景 在时序数据库中&#xff0c;资源的操作是一个复杂且关键的任务。这些操作通常涉及到多个步骤&#xff0c;每个步骤都可能会失败&#xff0c;导致资源处于不一致的状态。例如&#xff0c;一个用户可能想要在CnosDB集群中删除一个租户&#xff0c;这个操作可能需要删除租户…

颈椎前路caspar撑开器_“骨质增生”导致的颈椎病怎么破?

来源&#xff1a;《脊柱外科微创手术精要》作者&#xff1a;中日友好医院 邹海波此文是区别于颈椎间盘软性突出诊治一文&#xff0c;主要针对“骨质增生”导致的颈椎病(Spondylosis)进行介绍。传统的颈椎前路手术主要为颈椎病而设计。一度认为对颈椎病采用前路手术的主要好处在…

Struts2整合Freemarker生成静态页面

2019独角兽企业重金招聘Python工程师标准>>> 这是生成静态页面的预览&#xff1a; 其对应的模板文件&#xff1a; <table style"text-align:center;FONT-SIZE: 11pt; WIDTH: 600px; FONT-FAMILY: 宋体; BORDER-COLLAPSE: collapse" borderColor#3399ff…

快速幂、矩阵快速幂、快速乘法

快速幂 快速幂是我们经常用到的一种算法&#xff0c;快速幂顾名思义就是快速的幂运算。我们在很多题目中都会遇到幂运算&#xff0c;但是在指数很大的时候&#xff0c;我们如果用for或者是pow就会超时&#xff0c;这时候就用到了快速幂。 快速幂的原理就是&#xff0c;当求b^p的…

vue 前端显示图片加token_手摸手,带你用vue撸后台 系列二(登录权限篇)

完整项目地址&#xff1a;vue-element-adminhttps://github.com/PanJiaChen/vue-element-admin前言拖更有点严重&#xff0c;过了半个月才写了第二篇教程。无奈自己是一个业务猿&#xff0c;每天被我司的产品虐的死去活来&#xff0c;之前又病了一下休息了几天&#xff0c;大家…

注释工具_苹果已购丨Notability丨功能强大而简单易用的笔记及PDF注释工具

点击上方“天泽黑科技”右上角“...”点选“设为星标”点击加星★ 贴近你心 ❤今天给大家购买效率类排行第3名的 Notability &#xff01;大家在桌面 App store 登陆我的账号&#xff0c;搜索下载即可&#xff01;荣获 iPad、iPhone 和 Mac 的 Apple「编」爱新 App 殊荣&#x…

第四章 大网高级   NSSA

STUB、完全stub、NSSA、完全nssa实验要求&#xff1a;1、配置IP地址2、配置OSPF多区域3、配置 stub 末梢区域4、配置完全stub末梢区域5、配置 nssa 非纯末梢区域6、配置完全nssa非纯末梢区域7、配置两种协议相互注入重分发8、实现全网互通一、配置OSPF多区域二、配置rip v2三、…

[AlwaysOn Availability Groups] 健康模型 Part 2 ——扩展

[AlwaysOn Availability Groups] 健康模型 Part 2 ——扩展 健康模型扩展 第一部分已经介绍了AlwayOn健康模型的概述。现在是创建一个自己的PBM策略&#xff0c;然后设置为制定的归类。创建这些策略&#xff0c;创建之后修改一下配置&#xff0c;dashboard就会自动评估这些策略…

665. Non-decreasing Array - LeetCode

Question 665. Non-decreasing Array Solution 题目大意&#xff1a; 思路&#xff1a;当前判断2的时候可以将当前元素2变为4&#xff0c;也可以将上一个元素4变为2&#xff0c;再判断两变化后是否满足要求。 Java实现&#xff1a; public boolean checkPossibility(int[] nums…

如何制作印章_如何用Photoshop制作个性印章/文字图片

带印章和文字的图片&#xff0c;不仅可以作为个人的标签&#xff0c;更能直接表达照片的意境&#xff0c;让片子与众不同。那么&#xff0c;怎样才能给照片加印章和文字呢&#xff1f;或许方法有很多&#xff0c;甚至有多款App也可以直接做效果。但想要做出精细的效果&#xff…