Cypress EZ-USB FX3 DMA模式下的串口通讯

  

   由于公司设备升级后出了问题,需要对USB驱动进行修改,原本使用的是寄存器模式进行UART传输,但是由于FX3寄存器模式会出现长时间延时等待的问题,不得不对其传输模式进行修改。虽然赛普拉斯的EZ-USB FX3系列芯片功能强大,成本适中,但共享资源太少,API参考手册里面的干货不多,直接导致开发困难,出现问题只能去官方社区寻找答案。新模式的开发也不是一帆风顺,找来找去,只有在固件库中找到了UartLpDmaMode这个例程还比较相似。于是便在其基础上进行修改。

  在UartLpDmaMode例程中,其数据流通方向是这样的:

  只是从将接收到的数据进行了循环发送,这样一来,其生产者和消费者ID便很好设置,但是你无法对DMA通道进行直接操作,换句话说,你无法发送你想要发送的数据,也无法将你接收到的数据存入自己开辟的缓冲区中进行存储使用,当然这样并不是我想要的。

  我想要操作的数据传输是能够实现想传什么传什么,接收到的数据能想什么时候用就可以什么时候用。其数据流通就如同下图:

但是,我在初期对FX3的DMA消费者生产者理解不深,一度认为这是不能实现的,但经过几天的社区询问以及个人摸索,发现可以这样使用!由于期间走了很多弯路,深知百度找不到任何有关赛普拉斯有用资料的苦衷,现在把这段代码分享出来。

 

开发环境:EZ-USB FX3 Development Kit SDK1.3.4

开发板型号:CYUSB3KIT-003(CYUSB3014)

 

开发目的:实现串口DMA模式的数据发送以及接收,能够随意发送自己缓冲区中的数据,接收到的数据能够储存在个人开辟的缓冲区中

 

  1 /*此DEMO使用DMA模式,可以发送自己缓冲区中的数据,接收到数据后,可将接收到的数据存入全局变量glRxBuffer->buffer中。
  2  *注意:
  3  *    赛普拉斯FX3的DMA缓冲区大小最小是16个字节,缓冲区大小必须是16的倍数,也就是说,发送数据至少发送16个字节,发送的数据最大不能超过缓冲区的设定值,接收也一样,否则缓冲区未满,无法触发接收和发送!
  4  *如果与其他设备通讯,可以让其他设备强制发送16个字节的数据,自己取有效位使用。如果想一个字节一个字节的发送和接收,可以使用寄存器模式。
  5  */
  6 
  7 #include <cyu3system.h>
  8 #include <cyu3os.h>
  9 #include <cyu3error.h>
 10 #include <cyu3uart.h>
 11 
 12 #define CY_FX_UARTLP_THREAD_STACK       (0x0400)  /* UART application thread stack size */
 13 #define CY_FX_UARTLP_THREAD_PRIORITY    (8)       /* UART application thread priority */
 14 #define CY_FX_UART_DMA_TX_SIZE    (0)               /* DMA transfer size */
 15 #define CY_FX_UART_DMA_BUF_SIZE (16)              /* Buffer size */
 16 
 17 CyU3PThread UartLpAppThread;                      /* UART Example application thread structure */
 18 
 19 uint8_t testBuffer[16] = {0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xff};
 20 
 21 CyU3PDmaChannel glUartRXChHandle;
 22 CyU3PDmaChannel glUartTXChHandle;
 23 CyU3PDmaBuffer_t* glTxBuffer;
 24 CyU3PDmaBuffer_t* glRxBuffer;
 25 uint8_t ClearFlag = 0;
 26 
 27 /* Application error handler */
 28 void
 29 CyFxAppErrorHandler (
 30         CyU3PReturnStatus_t apiRetStatus    /* API return status */
 31         )
 32 {
 33     /* Application failed with the error code apiRetStatus */
 34 
 35     /* Add custom debug or recovery actions here */
 36 
 37     /* Loop indefinitely */
 38     for (;;)
 39     {
 40         /* Thread sleep : 100 ms */
 41         CyU3PThreadSleep (100);
 42     }
 43 }
 44 /***********************************************************************************************
 45 *函数名 : SendData
 46 *函数功能描述 : 通过DMA模式 由串口发送数据
 47 *函数参数 : buffer-所需要发送的数据    len-发送数据的长度
 48 *函数返回值 : 无
 49 *注意:len最小为16
 50 ***********************************************************************************************/
 51 void SendData(uint8_t * buffer, unsigned int len)
 52 {
 53     CyU3PReturnStatus_t status;
 54     unsigned int i = 0;
 55     CyU3PDmaChannelGetBuffer(&glUartTXChHandle, glTxBuffer, 0);
 56     for(i = 0; i < len; i++)
 57     {
 58         glTxBuffer->buffer[i] = buffer[i];
 59     }
 60     CyU3PDmaChannelSetupSendBuffer(&glUartTXChHandle,glTxBuffer);
 61     status = CyU3PDmaChannelCommitBuffer(&glUartTXChHandle, 16, 0);
 62     if (status == CY_U3P_SUCCESS)
 63     {
 64 
 65     }
 66 }
 67 
 68 /***********************************************************************************************
 69 *函数名 : ReceivedDataCallBack
 70 *函数功能描述 : 接收缓冲区充满后的回调函数
 71 *函数参数 : chHandle-DMA通道的句柄    type-事件类型    input-输入
 72 *函数返回值 : 无
 73 *注意:形参已经被设置好,直接可以使用
 74 ***********************************************************************************************/
 75 void ReceivedDataCallBack(
 76         CyU3PDmaChannel   *chHandle, /* Handle to the DMA channel. */
 77         CyU3PDmaCbType_t  type,      /* Callback type.             */
 78         CyU3PDmaCBInput_t *input)
 79 {
 80     CyU3PReturnStatus_t status;
 81     if(type == CY_U3P_DMA_CB_PROD_EVENT)
 82     {
 83         //CyU3PDmaChannelSetWrapUp(&glUartRXChHandle);
 84         status = CyU3PDmaChannelGetBuffer(&glUartRXChHandle, glRxBuffer, 0);
 85         //测试用,将收到的信息在发送出去,此时测试为接收到16个字节的数据
 86         SendData(glRxBuffer->buffer, 16);
 87         //SendData(testBuffer, 16);
 88         ClearFlag = 1;
 89         if (status == CY_U3P_SUCCESS)
 90         {
 91             CyU3PDmaChannelDiscardBuffer(&glUartRXChHandle);
 92         }
 93     }
 94 }
 95 
 96 /* This function initializes the UART module */
 97 void
 98 CyFxUartDMAlnInit (void)
 99 {
100     CyU3PUartConfig_t uartConfig;
101     CyU3PDmaChannelConfig_t dmaConfig;
102     CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS;
103 
104     //开启DCache后 一定设置为32,未开启最好也设置成32,但也可设置为16,不影响使用
105     glTxBuffer = (CyU3PDmaBuffer_t*)CyU3PDmaBufferAlloc (32);
106     glRxBuffer = (CyU3PDmaBuffer_t*)CyU3PDmaBufferAlloc (32);
107 
108     /* Initialize the UART module */
109     apiRetStatus = CyU3PUartInit ();
110     if (apiRetStatus != CY_U3P_SUCCESS)
111     {
112         /* Error handling */
113         CyFxAppErrorHandler(apiRetStatus);
114     }
115 
116     /* Configure the UART
117        Baudrate = 115200, One stop bit, No parity, Hardware flow control enabled.
118      */
119     CyU3PMemSet ((uint8_t *)&uartConfig, 0, sizeof(uartConfig));
120     uartConfig.baudRate = CY_U3P_UART_BAUDRATE_115200;
121     uartConfig.stopBit = CY_U3P_UART_ONE_STOP_BIT;
122     uartConfig.parity = CY_U3P_UART_NO_PARITY;
123     uartConfig.flowCtrl = CyFalse;             //一定不能为真
124     uartConfig.txEnable = CyTrue;
125     uartConfig.rxEnable = CyTrue;
126     uartConfig.isDma = CyTrue; /* DMA mode */
127 
128     /* Set the UART configuration */
129     apiRetStatus = CyU3PUartSetConfig (&uartConfig, NULL);
130     if (apiRetStatus != CY_U3P_SUCCESS )
131     {
132         /* Error handling */
133         CyFxAppErrorHandler(apiRetStatus);
134     }
135 
136     /* Create a DMA Manual channel between UART producer socket
137        and UART consumer socket */
138     CyU3PMemSet ((uint8_t *)&dmaConfig, 0, sizeof(dmaConfig));
139     dmaConfig.size = CY_FX_UART_DMA_BUF_SIZE;
140     dmaConfig.count = 1;
141     dmaConfig.prodSckId = CY_U3P_LPP_SOCKET_UART_PROD;   //生产者为RX
142     dmaConfig.consSckId = CY_U3P_CPU_SOCKET_CONS;        //消费者
143     dmaConfig.dmaMode = CY_U3P_DMA_MODE_BYTE;
144     dmaConfig.notification = CY_U3P_DMA_CB_PROD_EVENT;   //缓冲区充满产生的事件,此事件触发回调函数
145     dmaConfig.cb = ReceivedDataCallBack;
146     dmaConfig.prodHeader = 0;
147     dmaConfig.prodFooter = 0;
148     dmaConfig.consHeader = 0;
149     dmaConfig.prodAvailCount = 0;
150     /* Create the channel */
151     apiRetStatus = CyU3PDmaChannelCreate (&glUartRXChHandle,
152             CY_U3P_DMA_TYPE_MANUAL_IN, &dmaConfig);
153 
154     if (apiRetStatus != CY_U3P_SUCCESS)
155     {
156         /* Error handling */
157         CyFxAppErrorHandler(apiRetStatus);
158     }
159 
160     dmaConfig.size = CY_FX_UART_DMA_BUF_SIZE;
161     dmaConfig.count = 1;
162     dmaConfig.prodSckId = CY_U3P_CPU_SOCKET_PROD;               //生产者CPU
163     dmaConfig.consSckId = CY_U3P_LPP_SOCKET_UART_CONS;          //消费者为TX
164     dmaConfig.dmaMode = CY_U3P_DMA_MODE_BYTE;
165     dmaConfig.notification = 0;
166     dmaConfig.cb = NULL;
167     dmaConfig.prodHeader = 0;
168     dmaConfig.prodFooter = 0;
169     dmaConfig.consHeader = 0;
170     dmaConfig.prodAvailCount = 0;
171 
172     /* Create the channel */
173     apiRetStatus = CyU3PDmaChannelCreate (&glUartTXChHandle,
174             CY_U3P_DMA_TYPE_MANUAL_OUT, &dmaConfig);
175 
176     if (apiRetStatus != CY_U3P_SUCCESS)
177     {
178         /* Error handling */
179         CyFxAppErrorHandler(apiRetStatus);
180     }
181     /* Set UART Tx and Rx transfer Size to infinite */
182     apiRetStatus = CyU3PUartTxSetBlockXfer(0xFFFFFFFF);
183     if (apiRetStatus != CY_U3P_SUCCESS)
184     {
185         /* Error handling */
186         CyFxAppErrorHandler(apiRetStatus);
187     }
188 
189     apiRetStatus = CyU3PUartRxSetBlockXfer(0xFFFFFFFF);
190     if (apiRetStatus != CY_U3P_SUCCESS)
191     {
192         /* Error handling */
193         CyFxAppErrorHandler(apiRetStatus);
194     }
195 
196     /* Set DMA Channel transfer size */
197     apiRetStatus = CyU3PDmaChannelSetXfer (&glUartRXChHandle, 0);
198     if (apiRetStatus != CY_U3P_SUCCESS)
199     {
200             /* Error handling */
201         CyFxAppErrorHandler(apiRetStatus);
202     }
203 
204     apiRetStatus = CyU3PDmaChannelSetXfer (&glUartTXChHandle, 0);
205     if (apiRetStatus != CY_U3P_SUCCESS)
206     {
207         /* Error handling */
208         CyFxAppErrorHandler(apiRetStatus);
209     }
210 }
211 
212 /* Entry function for the UartLpAppThread */
213 void
214 UartLpAppThread_Entry (
215         uint32_t input)
216 {
217     /* Initialize the UART Example Application */
218     CyFxUartDMAlnInit();
219 
220     //uint8_t testBuffer[8] = {0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8};
221     for (;;)
222     {
223 
224         //if中的语句,是为了接收完毕后清除缓冲区,如果不清除缓冲区,如果所发数据超过缓冲区长度,第二次发送时会将上次未发送完的数据发送过来。
225         if(ClearFlag == 1)
226         {
227             //SendData(glRxBuffer->buffer, 16);
228             CyU3PDmaChannelReset(&glUartRXChHandle);
229             CyU3PThreadSleep(10);
230             CyU3PDmaChannelSetXfer(&glUartRXChHandle,0);
231             ClearFlag = 0;
232         }
233         /* No operation in the thread */
234         CyU3PThreadSleep (100);
235     }
236 }
237 
238 /* Application define function which creates the threads. */
239 void
240 CyFxApplicationDefine (
241         void)
242 {
243     void *ptr = NULL;
244     uint32_t retThrdCreate = CY_U3P_SUCCESS;
245 
246     /* Allocate the memory for the threads */
247     ptr = CyU3PMemAlloc (CY_FX_UARTLP_THREAD_STACK);
248 
249     /* Create the thread for the application */
250     retThrdCreate = CyU3PThreadCreate (&UartLpAppThread,           /* UART Example App Thread structure */
251                           "21:UART_loopback_DMA_mode",             /* Thread ID and Thread name */
252                           UartLpAppThread_Entry,                   /* UART Example App Thread Entry function */
253                           0,                                       /* No input parameter to thread */
254                           ptr,                                     /* Pointer to the allocated thread stack */
255                           CY_FX_UARTLP_THREAD_STACK,               /* UART Example App Thread stack size */
256                           CY_FX_UARTLP_THREAD_PRIORITY,            /* UART Example App Thread priority */
257                           CY_FX_UARTLP_THREAD_PRIORITY,            /* UART Example App Thread priority */
258                           CYU3P_NO_TIME_SLICE,                     /* No time slice for the application thread */
259                           CYU3P_AUTO_START                         /* Start the Thread immediately */
260                           );
261 
262     /* Check the return code */
263     if (retThrdCreate != 0)
264     {
265         /* Thread Creation failed with the error code retThrdCreate */
266 
267         /* Add custom recovery or debug actions here */
268 
269         /* Application cannot continue */
270         /* Loop indefinitely */
271         while(1);
272     }
273 }
274 
275 /*
276  * Main function
277  */
278 int
279 main (void)
280 {
281     CyU3PIoMatrixConfig_t io_cfg;
282     CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
283 
284     /* Initialize the device */
285     status = CyU3PDeviceInit (0);
286     if (status != CY_U3P_SUCCESS)
287     {
288         goto handle_fatal_error;
289     }
290 
291     /* Initialize the caches. Enable both Instruction and Data Caches. */
292     status = CyU3PDeviceCacheControl (CyTrue, CyTrue, CyTrue);
293     if (status != CY_U3P_SUCCESS)
294     {
295         goto handle_fatal_error;
296     }
297 
298     /* Configure the IO matrix for the device. On the FX3 DVK board, the COM port 
299      * is connected to the IO(53:56). This means that either DQ32 mode should be
300      * selected or lppMode should be set to UART_ONLY. Here we are choosing
301      * UART_ONLY configuration. */
302     CyU3PMemSet ((uint8_t *)&io_cfg, 0, sizeof(io_cfg));
303     io_cfg.isDQ32Bit = CyFalse;
304     io_cfg.s0Mode = CY_U3P_SPORT_INACTIVE;
305     io_cfg.s1Mode = CY_U3P_SPORT_INACTIVE;
306     io_cfg.useUart   = CyTrue;
307     io_cfg.useI2C    = CyFalse;
308     io_cfg.useI2S    = CyFalse;
309     io_cfg.useSpi    = CyFalse;
310     io_cfg.lppMode   = CY_U3P_IO_MATRIX_LPP_UART_ONLY;
311     /* No GPIOs are enabled. */
312     io_cfg.gpioSimpleEn[0]  = 0;
313     io_cfg.gpioSimpleEn[1]  = 0;
314     io_cfg.gpioComplexEn[0] = 0;
315     io_cfg.gpioComplexEn[1] = 0;
316     status = CyU3PDeviceConfigureIOMatrix (&io_cfg);
317     if (status != CY_U3P_SUCCESS)
318     {
319         goto handle_fatal_error;
320     }
321 
322     /* This is a non returnable call for initializing the RTOS kernel */
323     CyU3PKernelEntry ();
324 
325     /* Dummy return to make the compiler happy */
326     return 0;
327 
328 handle_fatal_error:
329     /* Cannot recover from this error. */
330     while (1);
331 
332 }

 

 

 

实验效果:能够实现发送和接收,FX3将接收到的数据再发送给主机,如图:

将110行的 SendData(glRxBuffer->buffer, 16);改为111行的SendData(testBuffer, 16);能够实现,接收16位数据后,将testBuffer中的数据返回给主机,效果如图:

需要注意的是:DMA_BUFFER_SIZE的大小必须为16的倍数!!最小为16!!也就是说,一次至少需要发送或者接收16个字节的数据,或者说是将缓冲区填满的数据!!

 

转载于:https://www.cnblogs.com/Lxk0825/p/9632830.html

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

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

相关文章

springboot md5加密_实在!基于Springboot和WebScoket,写了一个在线聊天小程序

基于Springboot和WebScoket写的一个在线聊天小程序(好几天没有写东西了&#xff0c;也没有去练手了&#xff0c;就看了看这个。。。)项目说明此项目为一个聊天的小demo&#xff0c;采用springbootwebsocketvue开发。其中有一个接口为添加好友接口&#xff0c;添加好友会判断是否…

suse 启动oracle11g,SuSe10下Oracle11g文件系统模式安装及配置、网络配置与连接

SuSe10下Oracle11g文件系统模式安装及配置、网络配置与连接概述本课程主要讲解oracle数据库软件的安装及配置&#xff0c;以及数据库的创建过程和网络配置与连接等&#xff1b;同时讲解一些数据库安装过程中的常见问题解决办法。注意&#xff1a;本文当中引用的package_name均为…

Python pyenv

一、简介 一般在操作系统中我们会安装多个Python版本&#xff0c;所以在进行Python版本切换时会比较麻烦&#xff0c;pyenv就提供了一种简单的方式&#xff0c;能简易地在多个Python版本中进行切换的工具&#xff0c;它简单而优雅。pyenv有以下功能&#xff1a; 1&#xff09;进…

oracle 增加间隔分区,oracle分区表之间隔分区(oracle 11g) - 漫兮网

范围分区允许用户根据分区键列值的范围创建分区。下面是一个按范围分区表的示例&#xff1a;create table sales6(sales_id number,sales_dt date)partition by range (sales_dt)(partition p0701 values less than (to_date(2007-02-01,yyyy-mm-dd)),partition p0702 values l…

c++ try catch语句_再问你一遍,你真的了解try..catch(finally)吗???

定义首先来看下 MDN 的定义&#xff1a;The try...catch statement marks a block of statements to try and specifies a response should an exception be thrown.try...catch语句标记要执行的语句&#xff0c;并指定一个当有异常抛出时候的响应简短的一句的确描述了try...ca…

lamp架构,搭建一个网络平台

首先更改主机名和 hosts 安装软件包&#xff0c;设置启动服务 设置数据库密码 上传discuz论坛包 将discuz注册的用户名写在mariadb数据库中 解压discuz包 unzip discuz包 -d /var/www/html cd到upload下 cp -rf * /var/www/html 进入数据库 mysql -uroot -p create database…

MyEclipse中SVN的使用方法

1、 加载插件 svn-myeclipse插件site-1.10.2.zip&#xff0c;解压缩后&#xff0c;将文件夹下的所有文件拷贝到MyEclipse安装包下的MyEclipse 8.5\dropins文件夹下&#xff0c;然后重新打开myeclipse&#xff0c;会弹出一个报错窗口&#xff0c;不要管它&#xff0c;关闭后&…

oracle数据泵导出csv文件,数据泵expdp导出遇到ORA-01555和ORA-22924问题的分析和处理...

使用数据泵导出数据库数据时&#xff0c;发现如下错误提示&#xff1a;ORA-31693: Table data object "CAMS_CORE"."BP_EXCEPTION_LOG" failed to load/unload and is being skipped due to error:ORA-02354: error in exporting/importing dataORA-01555:…

Go程序开发---Go环境配置:CentOS6.5+Go1.8标准包安装

1.Go安装 1.1Go的三种安装方式 Go有多种安装方式&#xff0c;可以选择自己习惯的方式进行&#xff0c;这里介绍三种安装方式&#xff1a; 1&#xff09;Go源码安装 2&#xff09;Go标准包安装 3&#xff09;第三方工具安装 这里主要介绍下Go标准包在CentOS6.5系统中的安装方式 …

python矩阵乘法_鱼书——第一章 Python入门

one 第一章1.1 Python是什么Python是一个简单、易读、易记的编程语言&#xff0c;而且是开源的&#xff0c;可以免费地自由使用。Python可以用类似英语的语法编写程序&#xff0c;编译起来也不费力&#xff0c;因此我们可以很轻松地使用Python。特别是对首次接触编程的人士来说…

keepalived vip ping不通_【干货分享】OpenStack LVS负载均衡为什么不通?

背景介绍OpenStack环境Neutron 的安全组会向虚拟机默认添加 anti-spoof 的规则&#xff0c;将保证虚拟机只能发出&#xff0f;接收以本机Port为原地址或目的地址(IP、MAC)的流量&#xff0c;提高了云的安全性。但是LVS等需要绑定VIP的场景&#xff0c;默认流量是被拦截的。需要…

Docker安装ssh,supervisor等基础工具

2019独角兽企业重金招聘Python工程师标准>>> Docker安装ssh&#xff0c;supervisor等基础工具 需要提前下载好官方的ubuntu镜像&#xff0c;我这里使用的是ubuntu:14.04版本&#xff0c;这里安装了一些基础的工具ssh&#xff0c;curl&#xff0c;wget&#xff0c;vi…

nginx集群_windows环境下搭建简单Nginx+Tomcat集群

通俗点将&#xff0c;负载均衡就是因为访问流量太大&#xff0c;导致项目访问不流畅、甚至宕掉&#xff0c;所以通过一种分流的方式来缓解这种情况。一、 工具nginx-1.8.0apache-tomcat-6.0.33二、 目标实现高性能负载均衡的Tomcat集群&#xff1a;三、 步骤1、首先下载Nginx&a…

颜色传感器TCS230及颜色识别电路(转)

摘要 TCS230是美国TAOS公司生产的一种可编程彩色光到频率的传感器。该传感器具有分辨率高、可编程的颜色选择与输出定标、单电源供电等特点&#xff1b;输出为数字量&#xff0c;可直接与微处理器连接。文中主要介绍TCS230的原理和应用&#xff0c;以及色光和白平衡的知识&…

mysql命令行导入和导出数据

首先打开命令窗口,输入命令:mysql -h localhost -u selffabu -p 连接成功后,进行下面的操作 MySQL中导出CSV格式数据的SQL语句样本如下&#xff1a; Sql代码select * from test_info into outfile /tmp/test.csv fields terminated by , optionally enclosed by " esc…

7.组件连线(贝塞尔曲线)--从零起步实现基于Html5的WEB设计器Jquery插件(含源码)...

上节讲到如何创建组件&#xff0c;清除设计器视图&#xff0c;以及设计视图的持久化和恢复&#xff0c;本节将重点讲如何实现组件间的连线&#xff0c;前面章节有提到为了方便从持久化文件中恢复&#xff0c;组件和连线是分别存放的&#xff1a;nodes和lines对象&#xff0c;两…

定位排查工作流的计算结果数据量不符合预期的方法

近期有发现一些用户在咨询&#xff0c;为什么数据从数据源出来后&#xff0c;经过了一些计算&#xff0c;结果不符合预期了。最常见的是说&#xff0c;为什么我的数据在Mysql里有xx条&#xff0c;怎么到MaxCompute里算了下结果变了。因为这是两个不同的系统&#xff0c;我们又没…

canvas 插件_基于canvas的JavaScript 二维码生成工具——QRCanvas

介绍在我们日常的开发中&#xff0c;特别是在现代的社会环境下&#xff0c;二维码的应用可谓是丰富多彩&#xff0c;各种各样让人眼花缭乱的二维码&#xff0c;可见二维码已经渗透进我们生活的方方面面&#xff0c;也可以说目二维码确确实实方便了我们的生活。因为作为开发人员…

消息队列NetMQ 原理分析2-IO线程和完成端口

目录 前言介绍目的IO线程初始化IO线程Proactor启动Procator线程轮询处理socketIOObject总结前言 介绍 [NetMQ](https://github.com/zeromq/netmq.git)是ZeroMQ的C#移植版本,它是对标准socket接口的扩展。它提供了一种异步消息队列,多消息模式,消息过滤&#xff08;订阅&#xf…

VC连接mysql数据库错误:libmysql.lib : fatal error LNK1113: invalid machine 解决方法

VC连接MySQL的配置过程在上一篇博文中&#xff0c;不过当你设置好&#xff0c;以为万事大吉的时候&#xff0c;运行却出现这个错误&#xff1a;libmysql.lib : fatal error LNK1113: invalid machine type。 无效的机器类型&#xff0c;真的是很让人捉急。 发生这个错误的原因是…