microPython高级应用

内部文件系统

microPython支持标准的Python的文件模块,可以使用open()这类原生函数。

需要注意的是esp32上实时资源少,需要及时关闭掉一些file、socket。

创建一个文件

>>> f = open('data.txt', 'w')
>>> f.write('some data')
9
>>> f.close()

其中这个9是指write()函数写进去的字节数

查看一个文件

>>> f = open('data.txt')
>>> f.read()
'some data'
>>> f.close()

文件目录操作

>>> import os   # 引用os模块
>>> os.listdir()    # 查看当前目录下的所有文件
['boot.py', 'port_config.py', 'data.txt']
>>> os.mkdir('dir') # 创建目录
>>> os.remove('data.txt')   # 删除文件

esp启动顺序

首先运行_boot.py这个脚本,把文件系统挂载上,这个部分一般是固定的,不推荐用户来修改,可能会出很多奇怪的问题。

当文件系统挂载成功后,运行boot.py,在这个脚本里面,用户可以设置一些在REPL里面需要使用的变量或者函数,每次重启esp32,这个脚本也会运行一次,但是如果这个地方写错了代码, 比如进入了死循环之类的,你就需要重新刷固件了。

最后系统会从文件系统运行main.py(如果不存在,就不会运行),这个文件就是用来每次启动的时候运行用户程序而不是进入REPL的,对于一些小的脚本,你可以直接写成一个main.py名字的文件,不过也会推荐你把一个大应用分散来写,写成多个小程序,在main.py里面这么写就好了:

import my_app

my_app.main()

设置开机自启动的脚本

对boot.py和main.py这两个文件进行修改都可以,比如对main.py进行修改:

>>> file = open("main.py", 'w')
>>> file.write("""import time
... for i in range(0,10):
...     time.sleep(1)
...     print(i)""")
64
>>> file.close()

通过快捷键ctrl+D,软启动esp32,就能看到上面的效果了

>>>
PYB: soft reboot
0
1
2
3
4
5
6
7
8
9
MicroPython v1.9.1-394-g79feb956 on 2017-08-03; ESP32 module with ESP32
Type "help()" for more information.
>>>

网络socket应用

简单的连接WiFi和设置热点可以看上一篇教程,成功之后就可以考虑TCP socket连接了。

在这里我们可以用socket模块,但其实有更加方便的模块,urequests(u表示这个模块和标准python的模块相比有许多没有方法没有实现):

import urequests

r = urequests.get('http://www.baidu.com')   # 发起HTTP的GET请求
r.text  # 查看服务器返回的内容<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1">​</span>

urequests实现了主要的几个方法,比如get、post、put、delete这几种请求,在网络方面使用起来非常方便。 

microPython常用函数

microPython常用函数

microPython的函数很多

machine module

CPU主频

import machine

machine.freq()      # 获得当前CPU频率
machine.freq(160000000)     # 设置当前CPU频率

控制引脚

from machine import Pin

p0 = Pin(0, Pin.OUT)    # GPIO0设置为输出模式
p0.value(1)             # p0输出高电平
p0.value(0)             # p0输出低电平
p0.value()              # 当前p0设置的电平

p2 = Pin(2, Pin.IN)     # GPIO2设置为输入模式
p2.value()              # p2的电平
p3 = Pin(3, Pin.IN, Pin.PULL_UP)    # GPIO3设置为上拉的输入模式
p4 = Pin(4, Pin.OUT, value=1)   # 创建Pin对象同时设置初始电平

 

可以设置的GPIO有 0, 1, 2, 3, 4, 5, 12, 13, 14, 15, 16;其中1、3作为REPL的串口使用,16用于从睡眠状态唤醒,使用的时候都需要注意。

PWM

from machine import Pin, PWM

pwm0 = PWM(Pin(0))      # 通过Pin对象来创建PWM对象
pwm0.freq()             # 获得当前的PWM频率
pwm0.freq(1000)         # 设置PWM频率
pwm0.duty()             # 获得当前的PWM占空比
pwm0.duty(200)          # 设置占空比
pwm0.deinit()           # 关闭PWM

pwm2 = PWM(Pin(2), freq=500, duty=512) # 创建PWM同时设置参数

 

除了GPIO16都可以使用PWM,频率参数的范围是1到1000,占空比参数的范围是0到1023。

ADC

from machine import ADC

adc = ADC(0)    # 在ADC引脚上创建ADC对象
adc.read()      # 获取ADC值,范围是0-1024

 

软SPI

可以用于所有的引脚

from machine import Pin, SPI

spi = SPI(-1, baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4))   # 创建SPI对象

spi.init(baudrate=200000) # 设置波特率

spi.read(10)            # 读取10字节
spi.read(10, 0xff)      # 读取十字节,并写出0xff

buf = bytearray(50)     # 创建一个缓冲字节流
spi.readinto(buf)       # 读入到这个字节流
spi.readinto(buf, 0xff) # 读入字节流并发送0xff

spi.write(b'12345')     # 发送5个字节

buf = bytearray(4)      
spi.write_readinto(b'1234', buf) # 发送并读取到buf
spi.write_readinto(buf, buf) # 发送buf并读取到buf

 

硬件SPI

硬件SPI更快(达到80Mhz),但是只适用于特定的引脚:
MISO是GPIO12,MOSI是GPIO13,SCK是GPIO14

和软串口一样有同样的方法函数,只是构造函数不同

from machine import Pin, SPI

hspi = SPI(1, baudrate=80000000, polarity=0, phase=0)

 

SPI(0)被用于FlashROM,不对用户开放

I2C

I2C适用于所有的引脚

i2c = I2C(scl=Pin(5), sda=Pin(4), freq=100000)

i2c.readfrom(0x3a, 4)   # 从0x3a读取4字节
i2c.writeto(0x3a, '12') # 发送12到0x3a

buf = bytearray(10)     # 创建十字节的缓冲字节流
i2c.writeto(0x3a, buf)  # 发送字节流到0x3a

 

深度睡眠模式

连接GPIO16和reset引脚

import machine

# 配置RTC.ALARM0来唤醒设备
rtc = machine.RTC()
rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP)

# 检查是否reset是否是由唤醒引起的
if machine.reset_cause() == machine.DEEPSLEEP_RESET:
    print('woke from a deep sleep')

# 设置RTC.ALARM0在10秒后唤醒设备
rtc.alarm(rtc.ALARM0, 10000)

# 设备进入深度睡眠
machine.deepsleep()

 

定时器

from machine import Timer

tim = Timer(-1)
tim.init(period=5000, mode=Timer.ONE_SHOT, callback=lambda t:print(1))
tim.init(period=2000, mode=Timer.PERIODIC, callback=lambda t:print(2))

 

其中period的单位是毫秒

network module

连接WIFI

import network

wlan = network.WLAN(network.STA_IF) # 创建WLAN STA接口
wlan.active(True)       # 激活WLAN
wlan.scan()             # 扫描附近的WIFI
wlan.isconnected()      # 查看当前是否已经连上WIFI
wlan.connect('essid', 'password') # 连接到附近的WIFI
wlan.config('mac')      # 获得mac地址
wlan.ifconfig()         # 返回IP/子网掩码/网关/DNS地址

 

可以把下面这个函数放到boot.py里面,每次启动一行代码就能连接WIFI了

def do_connect(ssid, password):
    import network
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if not wlan.isconnected():
        print('connecting to network...')
        wlan.connect(ssid, password)
        while not wlan.isconnected():
            pass
    print('network config:', wlan.ifconfig())

 

创建WIFI

ap = network.WLAN(network.AP_IF) # 创建一个AP
ap.active(True)         # 激活这个AP
ap.config(essid='ESP-AP') # 设置这个AP的SSID

 

连接上WIFI之后就能进一步使用socket库了

time module

延时和计时

import time

time.sleep(1)               # 延时一秒
time.sleep_ms(500)          # 延时500毫秒
time.sleep_us(10)           # 延时10微秒
start = time.ticks_ms()     # 得到内部计时的某个时间点
delta = time.ticks_diff(time.ticks_ms(), start) # 计算过去的时间段的长度

 

单总线

单总线协议适用于所有的引脚

from machine import Pin
import onewire

ow = onewire.OneWire(Pin(12)) # 在GPIO12上创建单总线协议
ow.scan()               # 返回总线上的设备列表
ow.reset()              # 重置总线
ow.readbyte()           # 读取一个字节
ow.writebyte(0x12)      # 往总线写0x12
ow.write('123')         # 往总线写'123'
ow.select_rom(b'12345678') # 选择特定设备

 

ds18x20

用于DS18S20和DS18B20的驱动库

import time, ds18x20
ds = ds18x20.DS18X20(ow)
roms = ds.scan()
ds.convert_temp()
time.sleep_ms(750)
for rom in roms:
    print(ds.read_temp(rom))

 

DHT驱动

DHT适用于所有的引脚

import dht
import machine

d = dht.DHT11(machine.Pin(4))
d.measure()
d.temperature() # eg. 23 (°C)
d.humidity()    # eg. 41 (% RH)

d = dht.DHT22(machine.Pin(4))
d.measure()
d.temperature() # eg. 23.6 (°C)
d.humidity()    # eg. 41.3 (% RH)

 

在esp32上配置运行microPython

microPython是该团队针对微处理器(一般指无法运行Linux操作性系统)做出的一个python的实现,官方有一些支持的板子,esp32作为一块性能高于esp8266,同时也具备很不错的wifi、蓝牙功能的开发板,也在microPython的支持之中,当前开发文档参考microPython on esp8266,毕竟是同一类板子。

下载固件并烧写

https://micropython.org/download#esp32

另外需要esptool.py,通过pip来安装。

pip install esptool.py

首先最好擦除原有的固件

sudo esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash

接着把刚刚下载的固件烧写上去

sudo esptool.py --chip esp32 --port /dev/ttyUSB0 write_flash -z 0x1000 ~/Downloads/esp32-20170803-v1.9.1-394-g79feb956.bin

连接ESP32

在Linux上推荐使用picocom来打开串口连接ESP32,Windows直接使用putty也行,注意要指定115200的波特率

$ sudo apt-get install picocom
$ sudo picocom -b 115200 /dev/ttyUSB0

使用Python

 

用picocom打开串口之后,按一下板子上的rst,可以看到串口出来的是一个python的REPL(交互解释器),当前一般的开发方法是通过串口的这个解释器逐行写代码进去,但是重启之后就会失效,想要断电保存并上电自启动也行,但操作相对会比较麻烦,不在本文的讨论之内。

注意这里的python是python3.4加上一点点3.5的特性,支持绝大部分的python核心数据类型和一些核心库。

最简单的你可以测试一下一些简单的内建函数

这个REPL占用了esp32的UART0(GPIO1=TX,GPIO3=RX),不过它的tab补全非常给力,比pc上的iPython差一点,但比起PC上的python shell是好到哪里去都不知道了。

控制引脚

microPython通过一个叫machine的module来控制引脚

from machine import Pin

p0 = Pin(0, Pin.OUT)    # 设置GPIO0的output模式
p0.value(1)             # 设置IO0为高电平
p0.value(0)             # 设置IO0为低电平

 

比如下面的例子就能用一秒的间隔来闪烁LED

import time
from machine import Pin

p0 = Pin(0, Pin.OUT)
state = 0
for i in range(0, 15):
    p0.value(state)
    state = 1 - state
    time.sleep(1)

另外对于这种比较长的代码,可以事先在PC上写完,然后在REPL中通过CRTL+E进入粘贴模式,复制粘贴完之后CTRL+D就行了。

microPython还有WiFi、PWM、SPI、I2C等一系列功能,以后的文章中会一个一个讲过来。

Raspi-config的命令行用法

稍微多用过树莓派的朋友相信都用过raspi-config这个工具,通过它可以相对可视化的容易地改变树莓派的配置。
但是里面的有些操作假如我们想要用命令行直接运行而不想进入raspi-config那个界面,那要怎么做呢?

在这个代码里面可以看到一些细节。

很多命令都是成对出现的,比如和hostname相关的

  • raspi-config nonint get_hostnameraspi-config nonint get_hostname就是获得当前设置的hostname
  • raspi-config nonint do_hostname %s对应的就是设置hostname

设置启用I2C可以通过raspi-config nonint get_i2c 00表示开启,1表示关闭(不同的命令可能是不同的对应)。

当前一些命令有这么多

/* Command strings */
#define GET_CAN_EXPAND  "raspi-config nonint get_can_expand"
#define EXPAND_FS       "raspi-config nonint do_expand_rootfs"
#define GET_HOSTNAME    "raspi-config nonint get_hostname"
#define SET_HOSTNAME    "raspi-config nonint do_hostname %s"
#define GET_BOOT_CLI    "raspi-config nonint get_boot_cli"
#define GET_AUTOLOGIN   "raspi-config nonint get_autologin"
#define SET_BOOT_CLI    "raspi-config nonint do_boot_behaviour B1"
#define SET_BOOT_CLIA   "raspi-config nonint do_boot_behaviour B2"
#define SET_BOOT_GUI    "raspi-config nonint do_boot_behaviour B3"
#define SET_BOOT_GUIA   "raspi-config nonint do_boot_behaviour B4"
#define GET_BOOT_WAIT   "raspi-config nonint get_boot_wait"
#define SET_BOOT_WAIT   "raspi-config nonint do_boot_wait %d"
#define GET_SPLASH      "raspi-config nonint get_boot_splash"
#define SET_SPLASH      "raspi-config nonint do_boot_splash %d"
#define GET_OVERSCAN    "raspi-config nonint get_overscan"
#define SET_OVERSCAN    "raspi-config nonint do_overscan %d"
#define GET_CAMERA      "raspi-config nonint get_camera"
#define SET_CAMERA      "raspi-config nonint do_camera %d"
#define GET_SSH         "raspi-config nonint get_ssh"
#define SET_SSH         "raspi-config nonint do_ssh %d"
#define GET_VNC         "raspi-config nonint get_vnc"
#define SET_VNC         "raspi-config nonint do_vnc %d"
#define GET_SPI         "raspi-config nonint get_spi"
#define SET_SPI         "raspi-config nonint do_spi %d"
#define GET_I2C         "raspi-config nonint get_i2c"
#define SET_I2C         "raspi-config nonint do_i2c %d"
#define GET_SERIAL      "raspi-config nonint get_serial"
#define GET_SERIALHW    "raspi-config nonint get_serial_hw"
#define SET_SERIAL      "raspi-config nonint do_serial %d"
#define GET_1WIRE       "raspi-config nonint get_onewire"
#define SET_1WIRE       "raspi-config nonint do_onewire %d"
#define GET_RGPIO       "raspi-config nonint get_rgpio"
#define SET_RGPIO       "raspi-config nonint do_rgpio %d"
#define GET_PI_TYPE     "raspi-config nonint get_pi_type"
#define GET_OVERCLOCK   "raspi-config nonint get_config_var arm_freq /boot/config.txt"
#define SET_OVERCLOCK   "raspi-config nonint do_overclock %s"
#define GET_GPU_MEM     "raspi-config nonint get_config_var gpu_mem /boot/config.txt"
#define GET_GPU_MEM_256 "raspi-config nonint get_config_var gpu_mem_256 /boot/config.txt"
#define GET_GPU_MEM_512 "raspi-config nonint get_config_var gpu_mem_512 /boot/config.txt"
#define GET_GPU_MEM_1K  "raspi-config nonint get_config_var gpu_mem_1024 /boot/config.txt"
#define SET_GPU_MEM     "raspi-config nonint do_memory_split %d"
#define GET_HDMI_GROUP  "raspi-config nonint get_config_var hdmi_group /boot/config.txt"
#define GET_HDMI_MODE   "raspi-config nonint get_config_var hdmi_mode /boot/config.txt"
#define SET_HDMI_GP_MOD "raspi-config nonint do_resolution %d %d"
#define GET_WIFI_CTRY   "raspi-config nonint get_wifi_country"
#define SET_WIFI_CTRY   "raspi-config nonint do_wifi_country %s"
#define CHANGE_PASSWD   "(echo \"%s\" ; echo \"%s\" ; echo \"%s\") | passwd"

 

Thonny——树莓派上Python的最新IDE

Thonny是最新的Raspbian系统中直接自带的Python IDE,支持Python3.6,更新到最新的Raspbian之后无需安装其他,就能打开使用。

在Menu>Programming中就能找到这个IDE

 

打开之后可以看到主要是两个区域,包括一个代码编辑区和一个shell的窗口,前者用来编写代码,后者可以用来更加直接地交互。

与IDLE相比,Thonny还有一大堆更加强大的适合学习编程地特性,比如他的debug模式,在debug模式中可以逐行运行代码,同时可以看到所有对象或变量的状态,在其他的一些IDE里面,它们会需要用户来设置断点,但是Thonny不需要,它有更加方便的方法。

如何使用Thonny

在代码编辑区正常地编写代码,代码高亮是有的,当然补全还是不存在的,写完一部分代码之后单击上方的三角形来运行代码,运行结果就会在下方地shell窗口中显示出来。

 

用Thonny来Debug

选择View>Variables,就会有一个新的变量小窗口显示出来,并且可以看到当前的n的值(0),单击上方的Debug图标,就会开始调试模式,第一行会高亮,接着再点击Step Into就会高亮变量,接着点击,变量会变成他的高亮的值(10);另外单机Step Out就能跳出while这个循环。

在Thonny中理解递归

对于这样一段代码

n = 3

def count(n):
  if n > 0:
    print(n)
    count(n-1)
  else:
    print("Blast off!")

count(n)

通过Thonny的Debug模式,就能非常直观地来看懂这段递归的代码。

在Thonny中观察程序运行时的堆和对象

选择VIew > Heap和View > Objects,那么当你调试下面的面向对象的代码的时候,就能很方便地在调试过程中看每个对象的属性和方法。

class Animal():
  def __init__(self, c, n):
    self.creature = c
    self.name = n
    
  def get_creature(self ):
    return self.creature

  def get_name(self):
    return self.name
    
animals = []

animals.append(Animal("Dog", "Fido"))
animals.append(Animal("Cat", "Claws"))
animals.append(Animal("Mouse","Nibbles"))

for animal in animals:
  name = animal.get_name()
  creature = animal.get_creature()
  print(name + " is a " + creature)

 

总体而言,这是一个轻量级的、同时又有不错的调试模式的IDE,非常适合在树莓派上学习Python时使用。

 

 

 

 

dietpi.txt 快速配置上手

DietPi是所谓的超级简单系统,一般人都知道怎么操作他,他非常轻量,也很容易适合本土化.引用老外的话就是:

“I’m a Linux noob and I have been playing around with installing things on my new Raspberry Pi–the hard way–doing manual installs! The amount of hours that goes into something like this is staggering. And then I discovered DietPi just yesterday. What a time-saver!”

他大概就是说,我就说个菜鸟,但是用这个我发现我会使用RPI了.而且对比DietPi和RPI官方系统Raspbian还是差别挺大的.

首先Raspbian的官方系统比较笨重,他已经没对比了,他对比的是Raspbian Lite.明显各项指标都很强大,但是经过我们的”优化”调整后,这更强大.其中我们很熟悉Raspbian的config.txt,而dietpi,他也有dietpi.txt,功能远比config.txt强大.

我们先打开这个文件:

逐一介绍下:

  • Ethernet_Enabled,如果设置为1,就是用以太网功能,如果设置为0,就是不用以太网功能.
  • Wifi_Enabled,如果设置为1,就是用以太网功能,如果设置为0,就是不用以太网功能.
  • Wifi_SSID和Wifi_KEY就是你的WIFI名字和密码,如果你没有屏幕键鼠,还没有以太网线,更没有串口调试,这个就非常实用了.
  • Use_Static就是使用静态IP地址,下面就是他的配置了.
  • Hostname就是你在路由上看到的名字,也就是设备名,如果你有多个设备就得区分下,他默认是DietPi,比如我一个Pi 3一个Pi B+,那么我要区分就得改他名字.
  • Ethernet_Force_Speed就是强制以太网速率,0就是自动识别,一般够用了,接百兆网就是百兆,1是10M网,1000是100M网,1000就是千兆网了.
  • Swapfile_Size就是设定SWAP文件的大小,一般设置为1就是自动,0就是不做SWAP,当然不推荐禁用SWAP了,除非你卡非常小,如果不是1也不是0,就你设定一个SWAP大小了.
  • AUTO_Install_Enable第一次启动DietPi总有提示,然后安装软件,比如在吃饭前你刚烧写好个系统,然后还要插上去操作一番才能离开,如果使能这个开关,设置为1,那么,这都不是问题.烧写好,然后插卡,去吃饭,回来就好了.
  • AUTO_Global_Password全局密码,包括用户名啊,Mysql啊各种都是默认这个密码,改掉安全一些.
  • AUTO_DietpiSoftware_Install_ID就是自动安装软件,比如我想首次启动帮我安装好LAMP,那么找到LAMP套件的ID,然后写AUTO_DietpiSoftware_Install_ID=74 (假设LAMP的ID是74.),当然,还要使能AUTO_Install_Enable,然后烧写好之后去吃饭,吃饭后回来软件也装好了.当然,这里软件包甚至包括WordPress.
  • AUTO_DietpiSoftware_SSHServerIndex是选择SSH服务提供组件,默认是dropbear,也就是-1,如果要用openssh,选-2就可以了,dropbear一般够用,openssh当然也有更多功能,如果根本用不到SSH,可以选0,关闭,更省资源.
  • AUTO_DietpiSoftware_FileServerIndex是选择文件服务器提供组件,默认是不开的,你可以用-1 ftp方式,-2 samba方式.
  • AUTO_DietpiSoftware_LoggingIndex是日志记录模式,默认是-1,也就是ramlog,0是跟Raspbian Lite一样记录方式,选ramlog的话,重启日志就没了,但是磁盘(TF)读写少,选-2 ramlog并每小时保存是个折中的办法.
  • AUTO_DietpiSoftware_WebserverIndex是Web提供组件,需要配合LAMP等一起用哦,0就是Apache2,最费资源但是最多功能,-1是Nginx,-2是Lighttpd.最后一个最轻量,也最少功能.
  • AUTO_AutoStartTarget是设置启动后默认状态,0是烧写系统后默认的,就是命令行不登录,2就是桌面环境.
  • AUTO_Timezone就是自动设置时区,这个也是依靠AUTO_Install_Enable使能的,比如我们设置成Asia/Shanghai,就是国内时间了.
  • AUTO_Locale就是本地化,类似语言,这个也是依靠AUTO_Install_Enable使能的,看英文看不爽,先预设成中文就爽了.默认是en_GB,我们换成zh_CN.
  • AUTO_KeyboardLayout就是键盘布局设置,这个也是依靠AUTO_Install_Enable使能的,当然你没键盘设置什么都是白扯的,有键盘的话,设置这个为us,就符合我们中国人键盘了.
  • rpi_hdmi_output 是针对RPI的了,如果设置为0,节省点RAM,因为不用启动显示功能了,做服务器尤为好用.
  • cpu_governor就是CPU调节器,对于Pi 3来说,performance就是固定1.2G,powersave就是固定600MHz,默认ondemand就是没事情时候低主频,有事时候快速升高.
  • SambaClient_ComputerName,SambaClient_ShareName,SambaClient_Username.SambaClient_Password就是配置samba的用户名密码名称的,很好理解啦.
  • boot_wait_for_network默认是1,就是等网络连接,可以设置成0,不等网络连接就开机,开机后网络也是不受影响的.对于没有网络连接的人来说,大胆禁用吧,对于只有无线但是不想在配置文件设置密码的,也可以禁用.
  • dietpi_check_for_updates为1就是可以检查更新,否则不检查更新.默认当然更新.
  • ntpd_update_mode是NTP时间同步的时刻,默认是开机同步,其实国内环境开机同步很费时,可以设置成4,后台同步.
  • wifi_hotspot_ssid,wifi_hotspot_key,wifi_hotspot_channel没有WIFI又没有以太网怎么操作,那就让Pi成为热点吧,这三个参数设置热点,名称啊密码,这样设置后,你就可以通过连接热点方式连接Pi,而不需要路由等附件了.
  • serial_console_enabled就是是否开启串口登录,又不想开热点,又没法连网络,比如在飞机上,你还是想玩玩,那么就用串口吧,默认是0,1是开启,开启后Pi的蓝牙就不好用了.
  • prefer_ipversion可以指定是否支持IPV6,默认auto是自动检测,其实国内IPV6除了高校,其他都支持不太好,可以直接force到ipv4,就是参数填ipv4,这样就很方便了.
  • Apt_Raspbian_Mirror就是设置树莓派源,还在讨厌树莓派源特别慢?不如把源改成http://mirrors.ustc.edu.cn/raspbian/raspbian/ 在国内可是神速.
  • dietpi_vncserver_*,如果没有显示器,还想要图形界面,VNC是你的选择,以前Raspbian时候VNC分辨率就是很小,感觉不好用,现在可以在配置文件直接配置VNC分辨率了.

2017-07-22 最新镜像(国内镜像优化版)

最新官方镜像!

最新官方镜像!

最新官方镜像!

重要事情要说三遍,因为是2017-07-22的镜像,而官网目前依然是2017-07-05,而实际上这个2017-07-22也是官方镜像,大家放心下载,并且还注入了几个重要补丁,相信大家会比较喜欢:

  • 替换了树莓派的乌龟速度源到国内USTC源,速度全满.
  • 替换了默认的en_US为zh_CN,再也不报中文语言的错了.
  • 默认启动了ssh,再也烧写后还要再新建个文件了.
  • 百分百保证原汁原味官方系统,非修改系统文件做的补丁,含官方签名.
  • 提供Lite版本和完整版本下载的同事,还提供带图形界面的4GB TF卡版本.
  • 加入内核上的ADS1115模块,让AD模块更好用,更易用.(AD模块购买请到顶端淘宝商城更实惠.)

这个系统镜像因为是官方方法制作,原汁原味,不留后门,支持USB启动,支持CM核心板!

另外,制作工具地址:https://github.com/nickfox-taterli/pi-gen-chinese

镜像下载地址:https://mega.nz/#F!IjAUzSRR!U0acFJoVM7XvKruFl4OHpQ

辅助下载链接:

完整系统链接: http://pan.baidu.com/s/1kUJJ471 密码: 5iun

Lite系统链接: http://pan.baidu.com/s/1nv3aDS1 密码: r8bb

4G TF卡可烧写系统链接: http://pan.baidu.com/s/1mi9OsPy 密码: ikj4

 

 

十步配置TeamViewer远程控制Pi – 支持内网穿透

使用TeamViewer远程控制Pi有如下好处:

  1. 可穿透局域网,延迟较低.
  2. 账号管理,不会遗忘连接.
  3. 操作友好,移动设备可管理.
  4. 无需显示器即可配置完成.

但是,我们怎样才能通过TeamViewer远程操作树莓派呢?首先注意确定的你的板子是Pi 3的.如果不确定,请参考文章:http://www.52pi.net/archives/454

然后确定自己系统版本比较新,我使用的是目前截稿为止的2017-06-21-raspbian-jessie.

剩下的,你需要一根网线,还有耐心啦.

第一步:拉取TeamViewer的安装包.

wget https://dl.tvcdn.de//download/linux/version_12x/teamviewer-host_12.0.78433_armhf.deb

第二步:尝试安装.

sudo dpkg -i teamviewer-host_12.0.78433_armhf.deb

第三步:虽然第二步失败了,但是我们目的是让系统知道他缺了什么软件包.这才有这一步,如果你已经成功,略过此步.

sudo apt-get -f install

第四步:我们重新开始安装,这次就能成功安装了.

sudo dpkg -i teamviewer-host_12.0.78433_armhf.deb

第五步:因为我们烧写的系统有图形界面,默认TeamViewer要在图形配置,除非你没有图形界面才能在命令行下配置,我们并没有显示器,所以先使用raspi-config配置到仅命令行模式.

sudo raspi-config

选择Boot Options – Desktop / CLI – Console AutoLogin

第六步:逐步退出raspi-config的配置,这会重启你的Pi.然后重启后登陆,运行下面命令开始配置:

sudo teamviewer setup

第七步:输入账号密码密码,如果还没有账号,那么你需要在你的电脑端注册一个账号了.

注册账号请点击电脑端此位置:

树莓派提示:

第八步:输入用户名和密码后,会询问是否加入树莓派到你的机器列表,我们当然选y.

如果此时提示你需要邮件验证,请进行邮件验证,然后重新登录,无需退出本程序.

第九步:此时提示我们成功加入到分组内了.同时,电脑的TeamViewer上也出现了设备了.

树莓派提示:

电脑提示:

第十步:还原为图形界面登录.运行raspi-config.

sudo raspi-config

选择Boot Options – Desktop / CLI – Desktop AutoLogin

完成:逐步退出raspi-config的配置,这会重启你的Pi.大功告成了.

此时你可以使用电脑版,移动端版TeamViewer测试连接.

电脑端测试图:

移动端测试图:

不知道大家注意到没,我手机访问使用的是移动网络,并且依然可以访问到内网的Pi,而我是没有给我的Pi分配公网IP的哦.

 

#Raspbian C应用编程#strlen 和 sizeof 的区别

上一次已经做了个CPU温度频率记录器,细心的同学如果打开文件一看,就哭晕了.

跟想象中好大差别啊:

为什么这么多^@啊,原来这是0x00的转义字符啊,因为我们上一节只用到了sizeof,所以不管buf多大,我们都写了1K数据进去.简直是浪费.把sizeof换成strlen,每次生成字符串前都清空buf.

这样每次写入的数量就心中有数了,strlen获取的是字符串有效长度,sizeof获取的是字符串的整个容器大小.

经过上述调整的代码,看起来就不违和了.

要想学习更多Linux C知识,多多关注本站吧,本站所有调试基于树莓派学习,现在入手买个套件,更方便你更进一步哦.

程序下载:

cpu_logger (3KB)

#Raspbian C应用编程#Linux 文件I/O – 系统温度主频记录器

UNIX/Linux 的一个基本哲学是”一切皆文件”.不仅普通的文件,甚至连各种字符设备、 块设备、套接字等都被当成文件对待,尽管它们的类型差异很大,但 UNIX/Linux 为它们提 供的操作界面却是相同的. Linux 把大部分系统资源当作文件并呈现给用户,用户只需按照文件 I/O 的方式,就能完成数据的输入输出. Linux 文件按其代表的具体对象,可大致分类为:

  1. 普通文件,即一般意义上的文件、磁盘文件;
  2. 设备文件,代表的是系统中一个具体的设备;
  3. 管道文件、 FIFO 文件,一种特殊文件,常用于进程间通信;
  4. 套接字( socket)文件,主要用在网络通信方面.

文件 I/O 的常用操作方法有”打开”、”关闭”、”读”和”写”等.只要是文件,所有文件都有前面两种方法.系统提供了文件 I/O API,以函数的形式提供给应用程序调用.打开文件对应的函数是 open(),读文件对应的函数是 read(),写文件对应的函数是 write(),关闭文件对应的函数是 close()

文件描述符 是进程中用来表示某个文件的一个变量, 文件描述符的作用,类似于在排队取号,业务员(进程)通过叫号(文件描述符)就能找到来搞事的人(文件)

大多数 Raspbian系统中,可通过命令”ulimit -n”查询到这个数值的大小,但注意,不是所有Linux都有这个指令.

文件描述符 012 在Linux上有特殊意义,我们暂时可以不去理解他.只知道他们比较特殊就行了,所以实际上树莓派只有最多7312个同时打开文件.(难道还不够?)

另外文件操作要涉及几个头文件,死记硬背.要用到哪个函数,就用哪个头文件,就是这样的.

#include<sys/types.h> /* 定义数据类型,如 ssize_t, off_t 等 */
#include <fcntl.h> /* 定义 open, creat 等函数原型,创建文件权限的符号常量 S_IRUSR 等 */
#include <unistd.h> /* 定义 read, write, close, lseek 等函数原型 */
#include <errno.h> /* 与全局变量 errno 相关的定义 */
#include <sys/ioctl.h> /* 定义 ioctl 函数原型 */

我们这就上Pi实践下,还是使用VS + Visual GDB神奇组合.就算你不懂Linux各种繁琐指令也能写出不错的程序.如果还不是特别了解,就参考下之前的文章吧.

下面演示的例子,先以可写方式打开当前目录下的hello.txt文件,如果该文件不存在,则创建文件,再往文件中写入一个字符串Hello, welcome to 52pi.net!,把操作结果输出到终端后,关闭文件. 接着再次以只读模式打开该文件,读取刚才写入的数据,并把结果输出到终端最后关闭该文件.

代码:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>

int main(int argc, char *argv [])
{
	char sz_str [] = "Hello, welcome to 52pi.net!";
	char sz_filename [] = "hello.txt";
	int fd = -1;
	int res = 0;
	char buf[128] = {0x00};
	fd = open(sz_filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
	if (fd < 0)
	{
		printf("Open file %s failed,errno = %d.\n", sz_filename, errno);
		return -1;
	}
	
	res = write(fd, sz_str, sizeof(sz_str));
	printf("write %d bytes to %s \n", res, sz_filename);
	fsync(fd);
	close(fd);
	
	fd = open(sz_filename, O_RDONLY);
	if (fd < 0)
	{
		printf("Open file %s failed,errno = %d.\n", sz_filename, errno);
		return -1;		
	}
	
	res = read(fd, buf, sizeof(buf));
	buf[res] = '\0';
	printf("read %d bytes from file %s ,data = %s \n", res, sz_filename, buf);
	close(fd);
	
	return 0;
	
}

测试结果:

那么刚才代码里面的O_WRONLY都是什么定义呢,我们可以右键,转到定义去查看一下.


当然也可以看我解释:

  • O_RDONLY 以只读方式打开文件
  • O_WRONLY 以只写方式打开文件
  • O_RDWR 以可读写方式打开文件. 上述三种旗标是互斥的, 也就是不可同时使用, 但可与下列的旗标利用OR(|)运算符组合.
  • O_CREAT 若欲打开的文件不存在则自动建立该文件.
  • O_EXCL 如果O_CREAT 也被设置, 此指令会去检查文件是否存在. 文件若不存在则建立该文件, 否则将导致打开文件错误. 此外, 若O_CREAT 与O_EXCL 同时设置, 并且欲打开的文件为符号连接, 则会打开文件失败.
  • O_NOCTTY 如果欲打开的文件为终端机设备时, 则不会将该终端机当成进程控制终端机.
  • O_TRUNC 若文件存在并且以可写的方式打开时, 此旗标会令文件长度清为0, 而原来存于该文件的资料也会消失.
  • O_APPEND 当读写文件时会从文件尾开始移动, 也就是所写入的数据会以附加的方式加入到文件后面.
  • O_NONBLOCK 以不可阻断的方式打开文件, 也就是无论有无数据读取或等待, 都会立即返回进程之中.
  • O_NDELAY 同O_NONBLOCK.
  • O_SYNC 以同步的方式打开文件.
  • O_NOFOLLOW 如果参数pathname 所指的文件为一符号连接, 则会令打开文件失败.
  • O_DIRECTORY 如果参数pathname 所指的文件并非为一目录, 则会令打开文件失败.(Linux特有)

而第二项权限意思是这样的:

  • S_IRWXU00700 权限, 代表该文件所有者具有可读、可写及可执行的权限.
  • S_IRUSR 或S_IREAD, 00400 权限, 代表该文件所有者具有可读取的权限.
  • S_IWUSR 或S_IWRITE, 00200 权限, 代表该文件所有者具有可写入的权限.
  • S_IXUSR 或S_IEXEC, 00100 权限, 代表该文件所有者具有可执行的权限.
  • S_IRWXG 00070 权限, 代表该文件用户组具有可读、可写及可执行的权限.
  • S_IRGRP 00040 权限, 代表该文件用户组具有可读的权限.
  • S_IWGRP 00020 权限, 代表该文件用户组具有可写入的权限.
  • S_IXGRP 00010 权限, 代表该文件用户组具有可执行的权限.
  • S_IRWXO 00007 权限, 代表其他用户具有可读、可写及可执行的权限.
  • S_IROTH 00004 权限, 代表其他用户具有可读的权限
  • S_IWOTH 00002 权限, 代表其他用户具有可写入的权限.
  • S_IXOTH 00001 权限, 代表其他用户具有可执行的权限.

如果不指定,权限就是000了,000代表谁都对这个文件没办法.

从上述我们已经了解到文件基本读写,那么现在开始实践,已知Raspbian系统的核心0的主频是存在/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq文件,而CPU温度是存在于/sys/class/thermal/thermal_zone0/temp文件.我们读取这两个文件,定时写入到一个文件里面做记录.

所以,记录工程应该长这个样子.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>

#include <time.h>


int main(int argc, char *argv [])
{
	int cpu_freq_fd = -1;
	int cpu_temp_fd = -1;
	int cpu_logger_fd = -1;	
	
	char freq_buf[128] = {0x00};
	char temp_buf[128] = {0x00};
	char log_buf[1024] = {0x00};
	
	time_t rawtime; 
	struct tm * timeinfo; 
	
	cpu_freq_fd = open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq", O_RDONLY);
	cpu_temp_fd = open("/sys/class/thermal/thermal_zone0/temp", O_RDONLY);	
	cpu_logger_fd = open("cpu.log", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
	
	while (1)
	{
		lseek(cpu_freq_fd, 0, SEEK_SET); /* 回到文件的开始 */
		read(cpu_freq_fd, freq_buf, sizeof(freq_buf)); /* 读取文件 */
		
		lseek(cpu_temp_fd, 0, SEEK_SET); 
		read(cpu_temp_fd, temp_buf, sizeof(temp_buf)); 
		
		time(&rawtime); 
		timeinfo = localtime(&rawtime); 
		
		char *now_time = asctime(timeinfo);
		now_time[strlen(now_time) - 1] = 0;
		
		sprintf(log_buf,"%s - CPU = %d MHz - Temp = %d degC\n", now_time, atoi(freq_buf) / 1000, atoi(temp_buf) / 1000);		
		
		write(cpu_logger_fd, log_buf, sizeof(log_buf));
		fsync(cpu_logger_fd);
		
		sleep(1);
	}
	
	close(cpu_freq_fd);
	close(cpu_temp_fd);	
	close(cpu_logger_fd);		
	
	return 0;
	
}

执行效果,是不是很棒,这样就有一个监控程序了.通过程序不难看出,就是不断写cpu.log文件.然后休眠.

此处用到的两个工程:

cpu_temp_logger

file_wr