Hello World

使用Laravel发送邮件

以前习惯上是用phpmail,但是新的需求需要发附件,使用phpmail发送附件,总是失败,刚好看到Laravel框架自带Mail模块,于是试了试,还挺好用

1
2
3
4
5
6
7
8
9
10
$exaTitle = '邮件标题';
$datas    = array("文件名1"=> 文件流1, "文件名2"=> 文件流2);
//发送邮件
\Mail::raw ($exaTitle, function($message) use($datas, $exaTitle){
    $message->to(array('收件人数组'))->subject ($exaTitle);
    foreach($datas as $k => $v){
        \Log::info('【SendPhpExcel】--add mail:'.$k.'--length('.count($v).')');
        $message->attachData($v, $k);
    }
});

$message->attachData(),用来发送文件流,如果是已经存放到硬盘上的文件,可以用$message->attach($filePath)
——
over

Hello World 倒塌集

2147483647

如果你在你的mysql里看到了这个数,一定稍微停下来想想
两周前写的同步联系人的方法,定时执行,半小时一次,已有的更新,没有的插入新数据

1
2
3
4
5
6
7
8
9
10
11
12
13
if(count($contacts) > 0){
    foreach($contacts as $co){
        $c = Contacts::where('uin', $co['Uin'])->first();
        if(empty($c)){
            $c = new Contacts();
            $c->uin = $co['Uin'];
        }
        $c->nick_name    = $co['NickName'];
        $c->user_name    = $co['UserName'];
        $c->last_fri_uid = $friUin;
        $c->save();
    }
}

很简单地逻辑吧~~
因为是demo项目,写完以后正常跑着,就没怎么细看
今天看Contacts库里面。。。。。。x,已经十几万条数据了
可以实际上只有几十个联系人,稍微细看,NickName全是重的
当时就对着这段程序找bug,加日志,但是,真没发现问题

在仔细看错误的数据,uin字段都是2147483647。。。好像猜到问题了。
于是百度mysql int字段的长度,恩,2147483647正式int的最大长度,如果给更大的数,存进去的还是这个~~与你建表是给这个字段的length无关
而这里的uin,正是这样一个长度不定的字段
好吧,这坑掉的值
字段改成bigint,或者varchar都ok,考虑的uin是外部传来的数据,还是varchar靠谱些
然后,“date -r 2147483647”,返回“2038年 1月19日 星期二 11时14分07秒 CST”,呵呵,这就是所谓的2038年问题
以前时间也都是用int保存的,以后再用到的时候,要不要都改成bigint字段?~~~思考中

Hello World 软硬兼施

树莓派控制直流电机

使用树莓派控制直流电机,包括控制转速和转向,这里使用的是L293D驱动芯片,简单易用
芯片接线方式如下图所示

L293D可以控制两路直流电机,这里做个简单演示,只控制一路,所以只用到了一侧的管脚
需要树莓派的三个gpio口,分别连L293D的1、2、7
1是使能信号,写死成高电平就行了
2是pwm,“脉冲宽度调制”,也就是宽边宽度的方波,7需要的信号与2相同
2、7的区别是,2或7有pwm信号是,电机转向是相反的
呵呵,偷个懒,继续简化,这里在用到2,将接2的线头改插到7上,电机如果翻转,也就成功了
也就是说,实际演示树莓派只用了2个gpio口~~嘻嘻

然后再看怎么用树莓派产生pwm信号~很简单:

1
2
3
4
5
6
GPIO.setup(gpiox, GPIO.OUT)
p = GPIO.PWM(gpiox, frequency) #创建一个 PWM 实例:
p.start(dc)   # dc 代表占空比(范围:0.0 <= dc >= 100.0)
p.ChangeFrequency(freq)   # freq 为设置的新频率,单位为 Hz
p.ChangeDutyCycle(dc)  # 修改占空比,范围:0.0 <= dc >= 100.0
p.stop() 停止 PWM:

好了,下面是整体的测试代码~~~其实是在一个“呼吸灯”的基础上加了一个使能信号,对应的,看到的是电机加速-减速-加速的过程

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
#coding:utf-8 脉宽调制(PWM)输出
import time
import RPi.GPIO as GPIO
 
def init(pwm, en):
    GPIO.setmode(GPIO.BCM)
    #使能信号
    GPIO.setup(en, GPIO.OUT)
    GPIO.output(en, True)
    GPIO.setup(pwm, GPIO.OUT)
    p = GPIO.PWM(pwm, 50)
    p.start(0)
    try:
        while 1: #周期性修改占空比
            for dc in range(0, 101, 5):
                p.ChangeDutyCycle(dc);
                time.sleep(0.1)
            for dc in range(100, -1, -5):
                p.ChangeDutyCycle(dc);
                time.sleep(0.1)
    except KeyboardInterrupt:
        pass
    p.stop()
    GPIO.cleanup()
 
if __name__ == '__main__':
    init(20, 16)  # gpio20接L293D的2或7管脚,gpio16接1管脚

接线图如下(有点乱,电机的电源是一块12v的电池,没有出现在画面中,另外,呼吸灯还保留着)
另外,电机两极最好并联一个陶瓷电容,转动会更平滑:


————–over
———————-后记
如何用树莓派控制电机,进而控制小车的前进、后退、转向,这个问题困扰了我半个多月
大学四年,唯一值得炫耀的,是大三暑假时参加的电子设计大赛集训,后来还拿了一等奖,也是在那次的比赛作品中,接触到了可变频宽方波控制功率输出的思路,貌似现在满街跑的电动车也是这么控制车速的
这样,树莓派产生这种方波就行了,当时还不知道树莓派有专门的pmw输出,想的还是程序写循环、通过不同的sleep长度、输出方波。。。
然后下一个问题,方波信号是3.3v,怎么控制12v的电机?
开始的想法是继电器,但是继电器这东西,连变频方波,肯定不连续,估计效果会很差
两一个思路是三极管、场效应管放大,拿手头的三极管搭了一个两级的放大电路,不成功,而且第二级管子发热特别厉害~~这个思路肯定是通的,L293D内部也就是这玩意,只是咱水平不够
于是继续搜索解决方案,然后在“极客范”找到了类似功能的文章,不过它讲的貌似是老版的树莓派,产生pmw信号的方法很麻烦;然后最后找到一篇树莓派pmw信号实现呼吸灯的介绍,于是二者结合,有了上面的方案
~~呵呵,作为已有近10年没怎么搞过硬件的人,能搞得这个程度,自己还算满意 🙂

Hello World 软硬兼施

使用树莓派驱动超声测距模块

这里用的模块,是SRF04超声测距模块,淘宝上买的,10块钱,加八块运费

测距的时序图如下:

想给触发信号trig一个约10us的高电平,模块会发送测距信号,回响信号echo会输出一个高电平,高电平的次序时间,与检测距离成正比,这就是该模块超声定位的基本原理
先面是相关的pytho代码

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
#srf04.py coding:utf-8 srf04超声测距模块驱动
import RPi.GPIO as GPIO
import time
from time import ctime, sleep
 
__gproTrig = 16    trig
__gproEcho = 12    echo
#初始化输入、输出gpio口
def init():
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(__gproTrig, GPIO.OUT)
    GPIO.setup(__gproEcho, GPIO.IN)
 
def measure():
    #确保启动前为低电平
    GPIO.output(__gproTrig, False)
    time.sleep(0.0001)
    #启动测距
    GPIO.output(__gproTrig, True)
    time.sleep(0.00001) #10us
    GPIO.output(__gproTrig, False)
    #开始记时
    start   = 0
    stop    = 0
   #         print("measure--1")
    while start == 0 or stop == 0:
        val     = GPIO.input(__gproEcho)
        if stop == 0 and start == 0 and val == 1:
   #         print("measure--2")
            start = time.time()
        if start > 0 and stop == 0 and val == 0:
      #      print("measure--3")
            stop = time.time()
    #根据驱动公式计算测距结果
    elapsed = stop - start
    distance = (elapsed * 34300)/2
    return distance
 
if __name__ == '__main__':
    init()
    for i in range(300)://五分钟测试
     #   print("srf05-start:", i)
        dis = measure()
        print('--------------dis:', dis)
        sleep(1)

over~
~~~~~~后记
其实这个超声模块已经到手很久了,但是看到驱动要使用10us信号后,就一直纠结怎么来做10us的时钟,测试用python的sleep实现时钟,又特别不精确,那么,就需要100MHz的晶振,可晶振怎么接到树莓派上。。。于是就卡到这里了。
后来偶然搜到了类似模块的驱动方式,才发现其实是我想多了,要什么晶振,sleep足够了~~~嘿嘿,照着这种思路做下去,居然真的成功了
很多事情就是这样:先有一个大概的思路,没有更好地办法的情况下,就先照着这个思路走,大部分时候都能走的过去

——本文为原创,转载请注明出处 昆仑的山头

Hello World 日志

微信支付的又一个坑

    从前年微信支付刚公测开始,前后接了三次微信支付。。。这次再接,居然还是磕磕绊绊,今天半个下午,都被一个下面这个错误提示误导了:
         getBrandWCPayRequest:fail_no permission to execute
    而且还不是总是出这个错误,有时是能正常支付的
    一般,出现这个错误,是因为微信支付授权地址不对,可是检查了n次,支付授权地址、js授权域名、oauth授权地址,都没发现问题
    然后怀疑签名错误,于是对比公钥,修改公钥,重新上传证书
    。。。总之,折腾了N次,还是不行
    ~~软件开发就是这样,如果一个问题,所有可能的原因都不是原因,那就剩下最后一个不可能的原因了:
    因为业务需要,这个项目要接入两个微信公众号,为了开发方便,两个公众号的代码是一起的,支付授权的url地址也就是一起的~~或许这就是原因
    设法将支付授权url地址区分开~~~问题解决!!
    猜测微信的“支付授权地址”是这样工作的,在微信客户端内,存在一个“支付授权地址–微信公众号”的缓存,而非“微信公众号–支付授权地址”,缓存更新不及时,就会出现上面的错误表现
——
btw:
    由于微信并未修改内置浏览器的内核,所以内置浏览器的很多特殊特性,都是微信webview通过外围的ios、android程序加入的
    比如新出的摇一摇页面获取openid/跳转关注页面,其实不过是再摇一摇出来的页面里种了一个cookie标记,如果你从摇一摇的页面退出来,再通过url直接进入这个页面,还可能调摇一摇的jsapi
    再比如oauth授权,如果A帐号进过你得站点,切换到B帐号后在,再进你得站点,用户身份还是A…因为cookie还在
    不过,实事求是的说,微信的jsapi确实很NB,将大量的原生应用的权限授权给了webview,大大扩展了web开发的可能性
    相对于微信的webview,phonegap这类专业号称使用webview做出原生应用的东西,就是个渣渣~~

Hello World

[转]Laravel框架数据库CURD操作、连贯操作总结

这篇文章主要介绍了Laravel框架数据库CURD操作、连贯操作、链式操作总结,本文包含大量数据库操作常用方法,需要的朋友可以参考下

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//--------Selects
//检索表中的所有行
$users = DB::table('users')->get();
foreach ($users as $user){
  var_dump($user->name);
}
 
//从表检索单个行
$user = DB::table('users')->where('name', 'John')->first();
var_dump($user->name);
 
//检索单个列的行
$name = DB::table('users')->where('name', 'John')->pluck('name');
 
//检索一个列值列表
$roles = DB::table('roles')->lists('title');
 
//该方法将返回一个数组标题的作用。你也可以指定一个自定义的键列返回的数组
$roles = DB::table('roles')->lists('title', 'name');
 
//指定一个Select子句
$users = DB::table('users')->select('name', 'email')->get();
$users = DB::table('users')->distinct()->get();
$users = DB::table('users')->select('name as user_name')->get();
 
//Select子句添加到一个现有的查询$query = DB::table('users')->select('name');
$users = $query->addSelect('age')->get();
 
//---------where
$users = DB::table('users')->where('votes', '>', 100)->get();
 
//OR
$users = DB::table('users')->where('votes', '>', 100)->orWhere('name', 'John')->get();
 
//Where Between
$users = DB::table('users')->whereBetween('votes', array(1, 100))->get();
 
//Where Not Between
$users = DB::table('users')->whereNotBetween('votes', array(1, 100))->get();
 
//Where In With An Array
$users = DB::table('users')->whereIn('id', array(1, 2, 3))->get();
$users = DB::table('users')->whereNotIn('id', array(1, 2, 3))->get();
 
//Using Where Null To Find Records With Unset Values
$users = DB::table('users')->whereNull('updated_at')->get();
 
//Order By, Group By, And Having
$users = DB::table('users')->orderBy('name', 'desc')->groupBy('count')->having('count', '>', 100)->get();
 
//Offset & Limit
$users = DB::table('users')->skip(10)->take(5)->get();
//--------连接
//Joins
//查询构建器也可以用来编写连接语句。看看下面的例子:
//Basic Join Statement
DB::table('users')
  ->join('contacts', 'users.id', '=', 'contacts.user_id')
  ->join('orders', 'users.id', '=', 'orders.user_id')
  ->select('users.id', 'contacts.phone', 'orders.price')
  ->get();
 
//左连接语句
DB::table('users')
  ->leftJoin('posts', 'users.id', '=', 'posts.user_id')
  ->get();
  DB::table('users')
  ->join('contacts', function($join)
  {
  $join->on('users.id', '=', 'contacts.user_id')->orOn(...);
  })
  ->get();
  DB::table('users')
  ->join('contacts', function($join)
  {
  $join->on('users.id', '=', 'contacts.user_id')
  ->where('contacts.user_id', '>', 5);
  })
  ->get();
//--------分组
 
//有时候,您可能需要创建更高级的where子句,如“存在”或嵌套参数分组。Laravel query builder可以处理这些:
DB::table('users')
  ->where('name', '=', 'John')
  ->orWhere(function($query){
    $query->where('votes', '>', 100)
      ->where('title', '<>', 'Admin');
  })->get();
//上面的查询将产生以下SQL:
select * from users where name = 'John' or (votes > 100 and title <> 'Admin')
 
//Exists Statements
DB::table('users')->whereExists(function($query){
  $query->select(DB::raw(1))
  ->from('orders')
  ->whereRaw('orders.user_id = users.id');
})->get();
//上面的查询将产生以下SQL:
select * from userswhere exists (select 1 from orders where orders.user_id = users.id)
 
//--------聚合
//查询构建器还提供了各种聚合方法,如统计,马克斯,min,avg和总和。
//Using Aggregate Methods
$users = DB::table('users')->count();
$price = DB::table('orders')->max('price');
$price = DB::table('orders')->min('price');
$price = DB::table('orders')->avg('price');
$total = DB::table('users')->sum('votes');
 
//Raw Expressions
//有时您可能需要使用一个原始表达式的查询。这些表达式将注入的查询字符串,所以小心不要创建任何SQL注入点!创建一个原始表达式,可以使用DB:rawmethod:
//Using A Raw Expression
$users = DB::table('users')
    ->select(DB::raw('count(*) as user_count, status'))
    ->where('status', '<>', 1)
    ->groupBy('status')
    ->get();
 
//递增或递减一个列的值
DB::table('users')->increment('votes');
DB::table('users')->increment('votes', 5);
DB::table('users')->decrement('votes');
DB::table('users')->decrement('votes', 5);
 
//您还可以指定额外的列更新:
DB::table('users')->increment('votes', 1, array('name' => 'John'));
 
//Inserts
//将记录插入表
DB::table('users')->insert(
	array('email' => 'john@example.com', 'votes' => 0)
);
 
//将记录插入表自动增加的ID
//如果表,有一个自动递增的id字段使用insertGetId插入一个记录和检索id:
$id = DB::table('users')->insertGetId(
    array('email' => 'john@example.com', 'votes' => 0)
);
//注意:当使用PostgreSQL insertGetId方法预计,自增列被命名为“id”。
 
//多个记录插入到表中
DB::table('users')->insert(array(
    array('email' => 'taylor@example.com', 'votes' => 0),
    array('email' => 'dayle@example.com', 'votes' => 0),
));
 
//--------Updates
//更新一个表中的记录
DB::table('users')
    ->where('id', 1)
    ->update(array('votes' => 1));
 
//--------Deletes
//删除表中的记录
DB::table('users')->where('votes', '<', 100)->delete();
 
//删除表中的所有记录
DB::table('users')->delete();
 
//删除一个表
DB::table('users')->truncate();
 
//--------Unions
//查询构建器还提供了一种快速的方法来“联盟”两个查询:
$first = DB::table('users')->whereNull('first_name');
$users = DB::table('users')->whereNull('last_name')->union($first)->get();
//unionAll方法也可以,有相同的方法签名。
  
//Pessimistic Locking
//查询构建器包括一些“悲观锁定”功能来帮助你做你的SELECT语句。  运行SELECT语句“共享锁”,你可以使用sharedLock方法查询:
DB::table('users')->where('votes', '>', 100)->sharedLock()->get();
 
//更新“锁”在一个SELECT语句,您可以使用lockForUpdate方法查询:
DB::table('users')->where('votes', '>', 100)->lockForUpdate()->get();
 
//--------缓存查询
//你可以轻松地缓存查询的结果使用记忆法:
$users = DB::table('users')->remember(10)->get();
 
//在本例中,查询的结果将为十分钟被缓存。查询结果缓存时,不会对数据库运行,结果将从默认的缓存加载驱动程序指定您的应用程序。  如果您使用的是支持缓存的司机,还可以添加标签来缓存:
$users = DB::table('users')->cacheTags(array('people', 'authors'))->remember(10)->get();

转自:http://www.jb51.net/article/54713.htm

Hello World 业界杂谈

QCon琐记

上周有机会参加了一天半的QCon,虽然感觉QCon越来越水,但是还是有些收获的,这里简单记录下来

Nodejs

其实,这次QCon没有nodejs的主题[汗]…,正因为没有,反而说明nodejs的热度已经过去了。

曾经火了两年,现在,曾经感兴趣的都已经体验过了,估计和我感受一样,nodejs不过是前端工程师偶尔玩玩后端的玩具,真正适合用nodejs的项目并不多。

而从前端js迁移到后端nodejs的学习成本,并不亚于从0开始学php这类简单脚本语言!

除了学习成本高,nodejs其他两个让人不爽的地方:

  1. 异步,导致代码回调嵌套太深,而后来给出的解决方案又太麻烦,可操作性不强
  2. npm库太乱,很多工具包更新不及时

而所谓统一前后端语言,个人觉得也完全没有必要:分开前后端,让开发者更清楚Http的界限在哪儿 ,哪些是跑在你服务器里的,哪些将运行在用户浏览器里。前后端的工作方式差别太大,所以了解这些,对开发者很重要

不过瑕不掩瑜,碰到需要webscoket的地方,nodejs还是很有优势的,去年年初做的一个nodejs小项目现在跑的还很平稳

全栈开发

所谓“全栈开发”,现在还没有统一的定义,大部分人得理解,就是一个人可以解决前后端的所有开发,至于说还要解决UI、测试,甚至还要自己扛机器,那就纯粹扯淡了

全栈到底是好还是不好,个人觉得视实际的公司、项目而定,如果是有很多业务的新公司,总是会有各种探索性的小项目,那么全栈工程师的优势明显:机动灵活,节约人力成本。

反之,如果是已经成体系的“大”项目,那么还是将前后端分开的好,这样即便于维护、也可以让各端做的更精。

因为人的精力有限,能做到“全栈”,就意味着都不会太专业。

小之美好

这是一个妹子讲自己所做的公共插件的主题,大意是,将功能庞大的服务项目,解体成一个个单独功能的小服务,其实这也是近几年软件工程的主要方向

将一个个小服务做好、做精,各个小服务都可以单独修改、单独上线,这样就能更加机动灵活、提升开发效率,降低维护成本

创业团队

开发人员如何创业,或者说技术如何参与到创业团队中,由于本人刚刚参加过一个创业团队,所以对相关的一个讲座深有感触

讲座提到一个4个人的创业团队,一个前端,三个后端,前端除了负责前端开发,还要负责交互和视觉;后端除了负责后端开发,还要负责产品功能。这样的一个团队,做出来的产品,并不亚于有很多产品大牛主持的东西

这里并不是说要干掉产品经理,而是尽量让技术也能参与到产品的设计中

如何让技术可以全身心的投入到开发中,最简单的办法不是拼命压缩项目周期,而是让技术本身觉得是在做自己的项目,所谓“将士用命 士子用心 文不贪财 武不怕死”,这样不仅开发效率更高,开发质量也会比仅停留在“简单做事”层面高的多

水电工

这个不是QCon的主题,纯粹是自己的一点心得

虽然我自己经常自嘲开发工作就像建筑工人,但二者还是有本质差别的:一个房子,必然是一砖一瓦建起来的,但是一个项目,却不一定真的需要一个字符一个字符的敲到电脑上~~

如果非要做个类比,开发者更像装修中水电工。水电工布设的各种管线,最终会被瓷砖、墙漆盖上。专业,或者说有良心的水电工会按照规程去布设管线,即使它们后来被盖上了,再来一个水电工要修改线路的时候,或者说其他人需要在墙上做打孔操作的时候,只要看到线路的入口和出口,按照一般的规律,就可以轻易的判断出线路的走向

更有甚者,在你之前,比如房子建设阶段就已经埋设了一些管线。如果一个水电工发现了这些基础设施,并且能够正确使用它们,就可以大大节省业主的成本

而专业的开发者正是需要这样的匠人精神:不见得什么东西都要自己从0做;自己做出的东西,也是对后续开发者友好的

轻应用

两、三年前,就在大家都忙着做所谓移动端“web app”的时候,却苦于找不到优秀的“母体”

使用普通手机浏览器?手机端浏览器种类比pc端更乱,兼容起来太难,而且不仅入口需要用户输入url,还需要注册之类的流程,用户入门门槛有点高

自己做app?自己能做app,干嘛还要搞体验要差一些的“web app”?

就在这时,微信公众平台很空出世,消息/扫码解决了入口问题,oauth解决了注册/登录问题,新出的jssdk,还可以实现很多普通web页无法实现的功能

可以预计,未来两年,基于微信的轻应用、小游戏会越来越多、越来越火

 

Hello World

微信分享icon设置的一个小技巧

当你的页面在微信内打开时,默认是有分享到朋友圈、发送给朋友等操作的。这两个操作都会带上一个icon,如果你没有调wx.onMenuShareTimeline之类的微信js接口,分享出处就没有比较,看起来很low,单微信js需要绑定域名,对于没有公号的“野页面”应该如何配置icon哪?

这里有个小技巧:需要将你的icon做出300*300的png(必须是300*300呦),然后将这个图片放在img里,再讲img放在一个隐藏的div里,这是再在微信里分享,icon图就是你设置的这个图标了

Hello World 软硬兼施

树莓派GPIO使用练习–点亮LED点阵

这里只是为了练习GPIO的使用,没有加任何的译码设备,也没加任何的放大设备,直接用树莓派的16个gpio引脚,连接一个8*8LED点阵的16个引脚,考虑到树莓派所能提供的电流不能太大,所以统一在点阵的8个阳极各加了一个1kΩ的电阻

8*8电阻的16个引脚,8个阳极,8个阴极,我们可以第一为R1~R8、C1~C8(考虑到点阵是方形的,所以不去区分行列,只区分阴阳,上面的R/C和“阴/阳”的对应关系,请根据实际共阴还是共阳区分清楚)

当我们给R1/C1两个管脚上电时(即在树莓派中,将R1对应的GPIO口拉到高电平,C1拉到低电平),第一行、第一列的这个点就会亮起来,同理,给R3/C5上电,[3, 5]的这个点会连起来

于是,我们可以通过这种方式依次点亮所有的点
。。。

于是,问题来了

如果我想同时点亮[3, 5]/[3, 6]/[4, 6]三个点,就需要同时拉高C3/C4,拉低R5/R6,可是,如果我做了这个操作,[4, 5]这个点也会亮起。。。这怎么办哪?

答案时,依次先点亮[3, 5]/[3, 6],熄灭这两个点,再点亮[4, 6],。。。熄灭[4, 6],点亮[3, 5]/[3, 6],如此往复,当这种切换的频率足够高时,由于认得视觉暂留,看到这三个点就是同时亮起的,也就是说,同一时刻,自会有单独一行、或者一列有点在发光

呵呵,很熟悉吧,电影、大屁股显示器什么的,和这个原理类似

好的,明白了原理,就可以动手写程序吧

这里使用树莓派最主流的编程语言:python,显示的东西,是“Hello word”,左右移动显示

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import RPi.GPIO as GPIO  #导入必要的python库
import time
 
#Hello World 字模
vhws = [
  [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
  [0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0],
  [0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0],
  [0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0],
  [0,0,0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,1,1,1,0,0,0,0,0,0],
  [0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,1,0,0,0,0,0,0],
  [0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0],
  [0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,1,1,1,0,0,0,0,0],
]
 
#左移还是右移
isRig = 1
vhwi = 0
#此函数返回当前时间点当前帧需要显示的8*8数组
def hwv():
  global isRig
  global vhwi
  l = len(vhws[0])
  if isRig &gt; 0:
    vhwi += 1
  else:
    vhwi -= 1
  if vhwi &gt;= (l - 8):
    isRig = 0
  if vhwi  0):
    if timeLine % 10 == 0:
      nowV = hwv()
    #双层循环实现的扫描显示  
    for i in range(0, len(nowV)):
      allOver()
      #拉低所有阴极
      GPIO.output(rs[i], GPIO.LOW)
      for j in range(0, len(nowV[i])):
        if nowV[i][j] &gt; 0:
          GPIO.output(cs[j], GPIO.HIGH) #点亮这个点
        else:
          GPIO.output(cs[j], GPIO.LOW)  #不点亮
        time.sleep(sleepTime)
    timeLine = timeLine - 1
  return
#ledtest 17 27 22 5 6 13 19 26 18 23 24 25 12 16 20 21
#这里是管脚对应关系
rs = [21, 20, 16, 12, 25, 24, 23, 18] #R1:13 R2:3 R3:4 R4:10 R5:6 R6:11 R7:15 R8:16
cs = [26, 19, 13, 6, 5, 22, 27, 17] #C1:5 C2:2 C3:7 C4:1 C5:12 C6:8 C7:14 C8:9
#开始
def startVs():
  GPIO.setmode(GPIO.BCM)
  for i in xrange(8):
    GPIO.setup(cs[i], GPIO.OUT)
    GPIO.setup(rs[i], GPIO.OUT)
  allOver()
  return
#关闭
def stopVs():
  GPIO.cleanup()
  return
#将所有管脚置为反响,即熄灭所有
def allOver():
  for i in xrange(8):
    GPIO.output(cs[i], GPIO.LOW)
    GPIO.output(rs[i], GPIO.HIGH)
  return
 
#timeLine = 1000
frames = 60
#显示一个8*8数组
def viewArr():
  timeLine = 1000
  sleepTime = 0.0001 #1 / (frames * 8)
  while(timeLine > 0):
    if timeLine % 10 == 0:
      nowV = hwv()
    for i in range(0, len(nowV)):
      allOver()#每次点亮前,先熄灭所有
      GPIO.output(rs[i], GPIO.LOW)
      for j in range(0, len(nowV[i])):
        if nowV[i][j] &gt; 0:
          GPIO.output(cs[j], GPIO.HIGH)  #点亮
        else:
          GPIO.output(cs[j], GPIO.LOW)   #不点亮
        time.sleep(sleepTime)  #扫屏的时延
  timeLine = timeLine - 1   #显示时常控制
return
 
if __name__ == '__main__':
  startVs()
  viewArr()
  stopVs()

下面是实际效果的几个截图:

下面两个是线路连接:

转载请注明出处:昆仑的山头

Hello World 微信开发

通过iBeacon接入微信摇一摇

什么是iBeacon?维基百科的定义是这样的:

一套iBeacon的部署由一个或多个在一定范围内发射传输他们唯一的识别码iBeacon信标设备组成。接收设备上的软件可以查找iBeacon并实现多种功能,比如通知用户,接收设备也可以通过链接iBeacons从iBeacon的通用属性配置服务来恢复价值。iBeacons不推送通知给接收设备(除了他们自己的ID),然而,手机软件可以使用从iBeacons接收到的信号来自己推送通知

不用太关注这个定义,微信摇一摇.周边功能,虽然使用到iBeacon,但其实只用到了它的“信标”功能,具体过程是这样的:

  1.  iBeacon基站通过不断地通过蓝牙广播自己的存在(实际有间隔,100~5000+ms)
  2. 用户手机打开微信摇一摇界面时,如果此时蓝牙是打开的,摇一摇就会就会在“人、歌曲、tv”之外多出一个“周边”,并且默认是“周边”
  3. 用户这时摇手机,就会出现第一步 iBeacon基站相关的信息

那么, 这个 iBeacon设备的信息如果设置哪?

  1. 首先,需要有一个开通支付功能的微信服务号
  2. 微信公号后台“新功能插件”里,选择“摇一摇周边”,申请
  3. 登录摇一摇后台(zb.weixin.qq.com),“设备管理”,新建设备,申请新设备的UUID/Major/Minor
  4. 将上述参数设置到你的iBeacon设备设备内

关于iBeacon基站,摇一摇后台就很多的推荐,另外,你也可以在淘宝购买,甚至可以自己购买蓝牙模块,通过简单配置,将其变成蓝牙基站

下面的这个链接,讲述了通过树莓派将HM-10蓝牙模块配置成iBeacon基站的方法,操作简单,亲测可用

http://www.xuebuyuan.com/2015895.html