esp32是双核开发板,多任务基于FreeRTOS,当多线程来看似乎也没太大问题。
以下用例代码使用Arduino IDE编译上传
在Arduino中使用digitalWrite来设置引脚的高低电平其实并不只是做了改变引脚寄存器数据这一件事,所以它的效率并不高,在需要高频输出的场景下就会出现瓶颈。
最近我在写大型LED矩阵屏驱动板的时候就遇到了这样的情况,一轮loop的速度太慢以至于watch dog以为程序死循环了而导致重启。后来我查来查去发现可以通过直接改变寄存器的数据来改变引脚的输出电平,而且官方头文件里其实也有对应的宏可以进行相关操作,但我怎么试都没成功,最后在一个官方demo里发现了一个函数,效率也同样不错,所以抄出来记录一下
1 2 3 4 5 6 7 8 9 |
void ICACHE_RAM_ATTR __digitalWrite(uint8_t pin, uint8_t val) { if(pin < 16){ if(val) GPOS = (1 << pin); else GPOC = (1 << pin); } else if(pin == 16){ if(val) GP16O |= 1; else GP16O &= ~1; } } |
只要调用 __digitalWrite(gpio引脚,0或1) 就可以了。
==========更新===========
把这个函数写成宏可以更进一步提高效率
1 2 3 4 5 6 7 8 9 |
//pin最好为常数,以便编译器优化掉判断 #define __digitalWrite(pin,val)\ if(pin < 16){\ if(val) GPOS = (1 << pin);\ else GPOC = (1 << pin);\ } else if(pin == 16){\ if(val) GP16O |= 1;\ else GP16O &= ~1;\ } |
原本我的电脑是两根8G阿斯加特内存插在两个通道各一个槽上组的双通道,最近发现有的时候不够用了,所以又买了一条16G的内存。
之所以这点破事也要写一篇文章,是因为这个过程里我一边调试一边蓝屏了十几次,觉得有必要记录一下。
这是原本的插法
现在是这个插法
两个通道上各凑满16G组成双通道32G
相关文档:http://zh.cppreference.com/w/cpp/thread/async
这只是一篇个人学习笔记,如有错误欢迎指出
咕了C++一段时间,我又回来学习了,这次是关于STL里自带的线程相关的模板函数 async 。
async可以非常方便地用来创建一个异步任务,不同于基于libuv那种事件轮回型的异步编程,这个异步是使用一个新的线程来执行任务,而coder不用自己去管理新的线程。
我刚开始学C++的时候似乎还没有lambda表达式这东西。这个blog的第一篇可见文章在2012年8月,还有一些更早的都是些垃圾水文被我删掉了,开设这个blog的时间我记得在学了web一段时间之后,在那之前我也在各种免费php空间搭过wordpress用过一段时间,后来废了。在更之前我还坚持用自己写的“佳佳空间”当blog用了很长一段时间(虽然后来终于还是放弃了,因为写得太垃圾)。推算下来可能要到9年多前了,大概就是小学的时候?反正是在2011年之前,而lambda表达式是C++11标准里的,所以那时候应该确实没有这东西。
好了回到正题。
C++的lambda表达式和js里的有点不一样,它可以自己选择是否打通函数范围之外的上下文,以使用外面的变量。还可以选择如何打通(引用外部变量和复制外部变量)。
lambda函数的结构长这样
1 2 3 |
[外部变量规则]{函数体}//没参数省略括号 [外部变量规则](参数){函数体}//省略返回类型指定 [外部变量规则](参数)->返回类型{函数体}//到C++11为止的完整形态 |
C++20又加了一个形式,暂时就不写在这了,毕竟2020年还没到呢不着急,而且也没编译器实现了。
C++是我学的第一个编程语言,也是我第一个放弃的编程语言,然后我就进入web路线了。
现在感觉转入web还是个不错的选择,学到的东西比只学C++要广泛的多,现在重新学一学C++来弥补一下某些时候性能上的缺陷。
翻了翻message事件的属性,没找到可以直接获取事件源iframe的属性,想想也没毛病,毕竟事件也可以是其它窗口post过来的。于是想了个曲线方法。
先让发送源获取焦点,然后获取焦点元素。
1 2 3 4 5 |
window.addEventListener('message',function(msg){ //做一些事来判断是不是某个iframe发送的消息 msg.source.focus(); var sourceFrame=document.activeElement; }); |
如果不想影响焦点的话,可以遍历一遍所有的iframe
1 2 3 4 5 6 7 8 9 10 11 |
function findIframe(win){ var fs=document.querySelectorAll('iframe'); for(var is=fs.length;is--;){ if(fs[is].contentWindow==win) return fs[is]; } } window.addEventListener('message',function(msg){ var iframe=findIframe(msg.source);//获取消息源 }); |
用javascript写了个base32的编解码函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
const charTable=[ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '=' ],allowedPeddingCount=[6,4,3,1,0]; function str_split(str,length){ if(typeof str !== 'string')return []; let a=[],i=0; length||(length=1); do{ a.push(str.substr(i,length)); i+=length; }while(i<str.length); return a; } const Base32={ encode:function(str,padding){ if(!str)return ''; let binaryString=''; for (let i = 0;i<str.length;i++) { let bin=str.charCodeAt(i).toString(2); binaryString+=('0'.repeat(8-bin.length)+bin); } let fiveBitBinaryArray=str_split(binaryString,5),base32=''; for(let i=0;i<fiveBitBinaryArray.length;i++){ let bin=fiveBitBinaryArray[i]; base32+=charTable[parseInt(bin+'0'.repeat(5-bin.length),2)]; } let x=binaryString.length%40; if (padding && x != 0) { if (x == 8)base32+=charTable[32].repeat(6); else if(x===16)base32+=charTable[32].repeat(4); else if(x===24)base32+=charTable[32].repeat(3); else if(x===32)base32+=charTable[32]; } return base32; }, decode:function(str){ if(!str)return ''; let paddingMatch=str.match(/\=+$/), paddingCharCount=paddingMatch?paddingMatch[0].length:0; if(allowedPeddingCount.indexOf(paddingCharCount)<0)return false; for (let i=0;i<4;i++){ if (paddingCharCount===allowedPeddingCount[i] && str.substr(-(allowedPeddingCount[i]))!=charTable[32].repeat(allowedPeddingCount[i])) return false; } str=str.replace(/\=+$/,''); let binaryString = ""; for (let i=0;i<str.length;i+=8) { let x=''; if (charTable.indexOf(str[i])<0)return false; for (let j=0;j<8;j++) { let bin=charTable.indexOf(str[i+j]).toString(2); x+='0'.repeat(5-bin.length)+bin; } let eightBits=str_split(x,8); for (let z = 0; z < eightBits.length; z++) { let y,cd=parseInt(eightBits[z],2,10); binaryString+=((y=String.fromCharCode(cd))||cd==48)?y:""; } } return binaryString; } } |
用一个看起来似乎有点不恰当的办法,用Error对象
1 |
(new Error).stack |
获取到的是字符串形式的调用栈。
不知道还有没有其它办法来获得调用栈。
由于解决这个问题花了我一些时间,所以记录一下说不定可以帮到其他人。
process.stdout是一个getter,所以我们不能用普通的替换来换掉process.stdout来拦截写入它的数据。同时,process.stdout是一个Writable Stream,所以也不能简单地直接从它里面获取写入的数据。
一开始我花了不少时间来研究怎么可以从这个Writable Stream里读出数据,但是这似乎太麻烦了,然后我甚至想到了利用child process来拦截数据。最后发现其实很简单,我们只要重新定义这个Getter就可以了。
1 2 3 4 5 6 7 8 |
var stream=require('stream'); var rawStdout=process.stdout,//先拿到原来的stdout newStdout=new stream.PassThrough();//创建一个passthrough流,这是一种特殊的Transform流,会直接把写入的数据吐出来 process.__defineGetter__('stdout',function(){//重新定义process.stdout的Getter return newStdout;//返回我们的passthrough流 }); |
这样我们就成功拦截到标准输出了,要注意,这段代码必须放在有任何输出之前,一旦在之前有了内容输出,它就没用了。
然后我们就可以自己决定怎么处理stdout了比如:
1 2 3 4 5 |
newStdout.pipe(rawStdout);//内容输出到控制台 newStdout.pipe(文件的writable stream);//内容写入文件 newStdout.pipe(其它可写流);//随你怎么处理 |
同理,process.stderr也可以这样拦截
1 2 3 |
var a=[123,234,345,567]; a.length=0;//清空了 |
上面的清空方式虽然非常不合字面含义,不过还确实清空了。。。
1 2 3 |
var a=[123,234,345,456]; a.splice(0);//清空了 |
这方法倒是符合字面含义了,不过这个操作会返回整个一个新的数组,所以可能性能不如上面的一种方法。
虽然我以前就吃过一次这个亏,不过昨天又犯这错误了。
虽然js里万物皆对象,不过也不是啥对象都可以加属性的,比如字符串。
1 2 3 4 |
var qweq='asdasdasdas'; qweq.miao=123; console.log(qweq.miao)//undefined |
所以字符串是没法添加属性的,同理,数字、Boolean也不能添加属性。
我发现它们都是传值型变量诶。因为本体只有一个值,所以不能添加属性吗。
node执行完所有代码以后就会退出(部分监听服务除外),如果不希望node立刻退出,只要加上一行
1 |
setInterval(function(){},9999999); |
node就不会退出了(除非出错
今天我才知道php脚本用php直接执行的时候是可以传入参数的,这样本地共享session就不需要建个服务器再访问啊什么的。
这里放个例子
文件a.php
1 2 3 4 |
<?php $args = getopt('a:b:'); print_r($args); ?> |
执行 php a.php -a miao -b 123
结果
1 2 3 4 5 |
Array ( [a] => miao [b] => 123 ) |
我在macbook上虚拟机里装了个Win10,装好了之后发现,一切都是那么的小,小的几乎看不清。因为这个macbook是Retina屏的,所以dpi比较高,于是东西都变小了。
我的标题里不直接写win10是因为我也不知道自定义项目大小是从哪个系统开始有的,没有这个功能的系统很简单,就是把分辨率按比例调低即可。
这种函数虽然百度一大把,不过我还是准备自己用很简单的代码写一个。现在访客暴涨然后我发现了在线人数显示功能好多bug,修了一下午。这个函数也是为此功能而写的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
function formatNum(num){ if(typeof num !=="number")return false;//判断是否是数字 num=num.toString();//字符化 var s=num.match(/e\+(\d+)$/),ext=0;; num=num.replace(/e.+$/,''); if(s)ext=Number(s[1]); //分割小数点两边 var tA=num.split('.'); if(tA.length>=2&&ext){//有小数点则分割开来处理(小数点后面可能还跟有科学记数法表示) if(tA.length>ext){ tA[0]+=tA[1].slice(0,ext-1); tA[1]=tA[1].slice(ext-1,tA[1].length-1); }else{ tA[0]+=(tA[1]+"0".repeat(ext-tA.length)); tA[1]=''; } } tA[0]=tA[0].split('');//拆字符 for(var i=tA[0].length;(i-=3)>0;){//插逗号 tA[0].splice(i,0,','); } return tA[0].join('')+(tA[1]?'.'+tA[1]:'');//连起来 } |
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
> formatNum(652342938443) < "652,342,938,443" > formatNum(98765424621365764512) < "98,765,424,621,365,770,000" //由于js最大能准确表示的数字为9,007,199,254,740,992,所以会得到这个结果 > formatNum(98765424621365764512465421654165343687117361543861243) < "987,654,246,213,657,700,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000" //由于原数在js中会转为科学记数法,所以用0替换 > formatNum(0.55555555555555555555555555555555555555555555555555555) < "0.5555555555555556" //小数点后没有千分位 > formatNum(98765424621.365764512465421654165343687117361543861243) < "98,765,424,621.36577" //同上 |