Merge remote-tracking branch 'LCTT/master'

This commit is contained in:
Xingyu Wang 2019-09-23 22:03:42 +08:00
commit 9f3cfeaca5
5 changed files with 727 additions and 741 deletions

View File

@ -0,0 +1,215 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-11378-1.html)
[#]: subject: (Getting started with Zsh)
[#]: via: (https://opensource.com/article/19/9/getting-started-zsh)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
Zsh 入门
======
> 从 Bash 进阶到 Z-shell改进你的 shell 体验。
![](https://img.linux.net.cn/data/attachment/album/201909/23/163910imr1z1qw1ruo9uqs.jpg)
Z-shellZsh是一种 Bourne 式的交互式 POSIX shell以其丰富的创新功能而著称。Z-Shell 用户经常会提及它的许多便利之处,赞誉它对效率的提高和丰富的自定义支持。
如果你刚接触 Linux 或 Unix但你的经验足以让你可以打开终端并运行一些命令的话那么你可能使用的就是 Bash shell。Bash 可能是最具有代表意义的自由软件 shell部分是因为它具有的先进的功能部分是因为它是大多数流行的 Linux 和 Unix 操作系统上的默认 shell。但是随着使用的次数越多你可能会开始发现一些细节可能能够做的更好。开源有一个众所周知的地方那就是选择。所以许多人选择从 Bash “毕业”到 Z。
### Zsh 介绍
Shell 只是操作系统的接口。交互式 shell 程序允许你通过称为*标准输入*stdin的某个东西键入命令并通过*标准输出*stdout和*标准错误*stderr获取输出。有很多种 shell如 Bash、Csh、Ksh、Tcsh、Dash 和 Zsh。每个都有其开发者所认为最适合于 Shell 的功能。而这些功能的好坏,则取决于最终用户。
Zsh 具有交互式制表符补全、自动文件搜索、支持正则表达式、用于定义命令范围的高级速记符,以及丰富的主题引擎等功能。这些功能也包含在你所熟悉的其它 Bourne 式 shell 环境中,这意味着,如果你已经了解并喜欢 Bash那么你也会熟悉 Zsh除此以外它还有更多的功能。你可能会认为它是一种 Bash++。
### 安装 Zsh
用你的包管理器安装 Zsh。
在 Fedora、RHEL 和 CentOS 上:
```
$ sudo dnf install zsh
```
在 Ubuntu 和 Debian 上:
```
$ sudo apt install zsh
```
在 MacOS 上你可以使用 MacPorts 安装它:
```
$ sudo port install zsh
```
或使用 Homebrew
```
$ brew install zsh
```
在 Windows 上也可以运行 Zsh但是只能在 Linux 层或类似 Linux 的层之上运行,例如 [Windows 的 Linux 子系统][2]WSL或 [Cygwin][3]。这类安装超出了本文的范围,因此请参考微软的文档。
### 设置 Zsh
Zsh 不是终端模拟器。它是在终端仿真器中运行的 shell。因此要启动 Zsh必须首先启动一个终端窗口例如 GNOME Terminal、Konsole、Terminal、iTerm2、rxvt 或你喜欢的其它终端。然后,你可以通过键入以下命令启动 Zsh
```
$ zsh
```
首次启动 Zsh 时,会要求你选择一些配置选项。这些都可以在以后更改,因此请按 `1` 继续。
```
This is the Z Shell configuration function for new users, zsh-newuser-install.
(q)  Quit and do nothing.
(0)  Exit, creating the file ~/.zshrc
(1)  Continue to the main menu.
```
偏好设置分为四类,因此请从顶部开始。
1. 第一个类使你可以选择在 shell 历史记录文件中保留多少个命令。默认情况下,它设置为 1,000 行。
2. Zsh 补全是其最令人兴奋的功能之一。为了简单起见,请考虑使用其默认选项激活它,直到你习惯了它的工作方式。按 `1` 使用默认选项,按 `2` 手动设置选项。
3. 选择 Emacs 式键绑定或 Vi 式键绑定。Bash 使用 Emacs 式绑定,因此你可能已经习惯了。
4. 最后你可以了解以及设置或取消设置Zsh 的一些精妙的功能。例如,当你提供不带命令的非可执行路径时,可以通过让 Zsh 来改变目录而无需你使用 `cd` 命令。要激活这些额外选项之一,请输入选项号并输入 `s` 进行设置。请尝试打开所有选项以获得完整的 Zsh 体验。你可以稍后通过编辑 `~/.zshrc` 取消设置它们。
要完成配置,请按 `0`
### 使用 Zsh
刚开始Zsh 的使用感受就像使用 Bash 一样这无疑是其众多功能之一。例如Bash 和 Tcsh 之间就存在严重的差异,因此如果你必须在工作中或在服务器上使用 Bash而 Zsh 就可以在家里轻松尝试和使用,这样在 Bash 和 Zsh 之间轻松切换就是一种便利。
#### 在 Zsh 中改变目录
正是这些微小的差异使 Zsh 变得好用。首先,尝试在没有 `cd` 命令的情况下,将目录更改为 `Documents` 文件夹。简直太棒了难以置信。如果你输入的是目录路径而没有进一步的指令Zsh 会更改为该目录:
```
% Documents
% pwd
/home/seth/Documents
```
而这会在 Bash 或任何其他普通 shell 中导致错误。但是 Zsh 却根本不是普通的 shell而这仅仅才是开始。
#### 在 Zsh 中搜索
当你想使用普通 shell 程序查找文件时,可以使用 `find``locate` 命令。最起码,你可以使用 `ls -R` 来递归地列出一组目录。Zsh 内置有允许它在当前目录或任何其他子目录中查找文件的功能。
例如,假设你有两个名为 `foo.txt` 的文件。一个位于你的当前目录中,另一个位于名为 `foo` 的子目录中。在 Bash Shell 中,你可以使用以下命令列出当前目录中的文件:
```
$ ls
foo.txt
```
你可以通过明确指明子目录的路径来列出另一个目录:
```
$ ls foo
foo.txt
```
要同时列出这两者,你必须使用 `-R` 开关,并结合使用 `grep`
```
$ ls -R | grep foo.txt
foo.txt
foo.txt
```
但是在 Zsh 中,你可以使用 `**` 速记符号:
```
% ls **/foo.txt
foo.txt
foo.txt
```
你可以在任何命令中使用此语法,而不仅限于 `ls`。想象一下在这样的场景中提高的效率:将特定文件类型从一组目录中移动到单个位置、将文本片段串联到一个文件中,或对日志进行抽取。
### 使用 Zsh 的制表符补全
制表符补全是 Bash 和其他一些 Shell 中的高级用户功能,它变得司空见惯,席卷了 Unix 世界。Unix 用户不再需要在输入冗长而乏味的路径时使用通配符(例如输入 `/h*/s*h/V*/SCS/sc*/comp*/t*/a*/*9/04/LS*boat*v`,比输入 `/home/seth/Videos/SCS/scenes/composite/takes/approved/109/04/LS_boat-port-cargo-mover.mkv` 要容易得多)。相反,他们只要输入足够的唯一字符串即可按 `Tab` 键。例如,如果你知道在系统的根目录下只有一个以 `h` 开头的目录,则可以键入 `/h`,然后单击 `Tab`。快速、简单、高效。它还会确认路径存在;如果 `Tab` 无法完成任何操作,则说明你在错误的位置或输入了错误的路径部分。
但是,如果你有许多目录有五个或更多相同的首字母,`Tab` 会坚决拒绝进行补全。尽管在大多数现代终端中,它将(至少会)显示阻止其进行猜测你的意思的文件,但通常需要按两次 `Tab` 键才能显示它们。因此,制表符补全通常会变成来回按下键盘上字母和制表符,以至于你好像在接受钢琴独奏会的训练。
Zsh 通过循环可能的补全来解决这个小问题。如果键入 `*ls ~/D` 并按 `Tab`,则 Zsh 首先使用 `Documents` 来完成命令;如果再次按 `Tab`,它将提供 `Downloads`,依此类推,直到找到所需的选项。
### Zsh 中的通配符
在 Zsh 中,通配符的行为不同于 Bash 中用户所习惯的行为。首先,可以对其进行修改。例如,如果要列出当前目录中的所有文件夹,则可以使用修改后的通配符:
```
% ls
dir0   dir1   dir2   file0   file1
% ls *(/)
dir0   dir1   dir2
```
在此示例中,`(/)` 限定了通配符的结果,因此 Zsh 仅显示目录。要仅列出文件,请使用 `(.)`。要列出符号链接,请使用 `(@)`。要列出可执行文件,请使用 `(*)`
```
% ls ~/bin/*(*)
fop  exify  tt
```
Zsh 不仅仅知道文件类型。它也可以使用相同的通配符修饰符约定根据修改时间列出。例如,如果要查找在过去八个小时内修改的文件,请使用 `mh` 修饰符(即 “modified hours” 的缩写)和小时的负整数:
```
% ls ~/Documents/*(mh-8)
cal.org   game.org   home.org
```
要查找超过(例如)两天前修改过的文件,修饰符更改为 `md`(即 “modified day” 的缩写),并带上天数的正整数:
```
% ls ~/Documents/*(+2)
holiday.org
```
通配符修饰符和限定符还可以做很多事情,因此,请阅读 [Zsh 手册页][4],以获取全部详细信息。
#### 通配符的副作用
要像在 Bash 中使用通配符一样使用它,有时必须在 Zsh 中对通配符进行转义。例如,如果要在 Bash 中将某些文件复制到服务器上,则可以使用如下通配符:
```
$ scp IMG_*.JPG seth@example.com:~/www/ph*/*19/09/14
```
这在 Bash 中有效,但是在 Zsh 中会返回错误,因为它在发出 `scp` 命令之前尝试在远程端扩展该变量(通配符)。为避免这种情况,必须转义远程变量(通配符):
```
% scp IMG_*.JPG seth@example.com:~/www/ph\*/\*19/09/14
```
当你切换到新的 shell 时,这些小异常可能会使你感到沮丧。使用 Zsh 时会遇到的问题不多(体验过 Zsh 后切换回 Bash 的可能遇到更多),但是当它们发生时,请保持镇定且坦率。严格遵守 POSIX 的情况很少会出错,但是如果失败了,请查找问题以解决并继续。对于许多在工作中困在一个 shell 上而在家中困在另一个 shell 上的用户来说,[hyperpolyglot.org][5] 已被证明其是无价的。
在我的下一篇 Zsh 文章中,我将向你展示如何安装主题和插件以定制你的 Z-Shell 甚至 Z-ier。
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/9/getting-started-zsh
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/bash_command_line.png?itok=k4z94W2U (bash logo on green background)
[2]: https://devblogs.microsoft.com/commandline/category/bash-on-ubuntu-on-windows/
[3]: https://www.cygwin.com/
[4]: https://linux.die.net/man/1/zsh
[5]: http://hyperpolyglot.org/unix-shells

View File

@ -1,507 +0,0 @@
wenwensnow is translating
Go on very small hardware (Part 1)
============================================================
How low we can  _Go_  and still do something useful?
I recently bought this ridiculously cheap board:
[![STM32F030F4P6](https://ziutek.github.io/images/mcu/f030-demo-board/board.jpg)][2]
I bought it for three reasons. First, I have never dealt (as a programmer) with STM32F0 series. Second, the STM32F10x series is getting old. MCUs belonging to the STM32F0 family are just as cheap if not cheaper and has newer peripherals, with many improvements and bugs fixed. Thirdly, I chose the smallest member of the family for the purpose of this article, to make the whole thing a little more intriguing.
### The Hardware
The [STM32F030F4P6][3] is impresive piece of hardware:
* CPU: [Cortex M0][1] 48 MHz (only 12000 logic gates, in minimal configuration),
* RAM: 4 KB,
* Flash: 16 KB,
* ADC, SPI, I2C, USART and a couple of timers,
all enclosed in TSSOP20 package. As you can see, it is very small 32-bit system.
### The software
If you hoped to see how to use [genuine Go][4] to program this board, you need to read the hardware specification one more time. You must face the truth: there is a negligible chance that someone will ever add support for Cortex-M0 to the Go compiler and this is just the beginning of work.
Ill use [Emgo][5], but dont worry, you will see that it gives you as much Go as it can on such small system.
There was no support for any F0 MCU in [stm32/hal][6] before this board arrived to me. After brief study of [RM][7], the STM32F0 series appeared to be striped down STM32F3 series, which made work on new port easier.
If you want to follow subsequent steps of this post, you need to install Emgo
```
cd $HOME
git clone https://github.com/ziutek/emgo/
cd emgo/egc
go install
```
and set a couple environment variables
```
export EGCC=path_to_arm_gcc # eg. /usr/local/arm/bin/arm-none-eabi-gcc
export EGLD=path_to_arm_linker # eg. /usr/local/arm/bin/arm-none-eabi-ld
export EGAR=path_to_arm_archiver # eg. /usr/local/arm/bin/arm-none-eabi-ar
export EGROOT=$HOME/emgo/egroot
export EGPATH=$HOME/emgo/egpath
export EGARCH=cortexm0
export EGOS=noos
export EGTARGET=f030x6
```
A more detailed description can be found on the [Emgo website][8].
Ensure that egc is on your PATH. You can use `go build` instead of `go install` and copy egc to your  _$HOME/bin_  or  _/usr/local/bin_ .
Now create new directory for your first Emgo program and copy example linker script there:
```
mkdir $HOME/firstemgo
cd $HOME/firstemgo
cp $EGPATH/src/stm32/examples/f030-demo-board/blinky/script.ld .
```
### Minimal program
Lets create minimal program in  _main.go_  file:
```
package main
func main() {
}
```
Its actually minimal and compiles witout any problem:
```
$ egc
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
7452 172 104 7728 1e30 cortexm0.elf
```
The first compilation can take some time. The resulting binary takes 7624 bytes of Flash (text+data), quite a lot for a program that does nothing. There are 8760 free bytes left to do something useful.
What about traditional  _Hello, World!_  code:
```
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
```
Unfortunately, this time it went worse:
```
$ egc
/usr/local/arm/bin/arm-none-eabi-ld: /home/michal/P/go/src/github.com/ziutek/emgo/egpath/src/stm32/examples/f030-demo-board/blog/cortexm0.elf section `.text' will not fit in region `Flash'
/usr/local/arm/bin/arm-none-eabi-ld: region `Flash' overflowed by 10880 bytes
exit status 1
```
_Hello, World!_  requires at last STM32F030x6, with its 32 KB of Flash.
The  _fmt_  package forces to include whole  _strconv_  and  _reflect_  packages. All three are pretty big, even a slimmed-down versions in Emgo. We must forget about it. There are many applications that dont require fancy formatted text output. Often one or more LEDs or seven segment display are enough. However, in Part 2, Ill try to use  _strconv_  package to format and print some numbers and text over UART.
### Blinky
Our board has one LED connected between PA4 pin and VCC. This time we need a bit more code:
```
package main
import (
"delay"
"stm32/hal/gpio"
"stm32/hal/system"
"stm32/hal/system/timer/systick"
)
var led gpio.Pin
func init() {
system.SetupPLL(8, 1, 48/8)
systick.Setup(2e6)
gpio.A.EnableClock(false)
led = gpio.A.Pin(4)
cfg := &gpio.Config{Mode: gpio.Out, Driver: gpio.OpenDrain}
led.Setup(cfg)
}
func main() {
for {
led.Clear()
delay.Millisec(100)
led.Set()
delay.Millisec(900)
}
}
```
By convention, the  _init_  function is used to initialize the basic things and configure peripherals.
`system.SetupPLL(8, 1, 48/8)` configures RCC to use PLL with external 8 MHz oscilator as system clock source. PLL divider is set to 1, multipler to 48/8 = 6 which gives 48 MHz system clock.
`systick.Setup(2e6)` setups Cortex-M SYSTICK timer as system timer, which runs the scheduler every 2e6 nanoseconds (500 times per second).
`gpio.A.EnableClock(false)` enables clock for GPIO port A.  _False_  means that this clock should be disabled in low-power mode, but this is not implemented int STM32F0 series.
`led.Setup(cfg)` setups PA4 pin as open-drain output.
`led.Clear()` sets PA4 pin low, which in open-drain configuration turns the LED on.
`led.Set()` sets PA4 to high-impedance state, which turns the LED off.
Lets compile this code:
```
$ egc
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
9772 172 168 10112 2780 cortexm0.elf
```
As you can see, blinky takes 2320 bytes more than minimal program. There are still 6440 bytes left for more code.
Lets see if it works:
```
$ openocd -d0 -f interface/stlink.cfg -f target/stm32f0x.cfg -c 'init; program cortexm0.elf; reset run; exit'
Open On-Chip Debugger 0.10.0+dev-00319-g8f1f912a (2018-03-07-19:20)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
debug_level: 0
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
none separate
adapter speed: 950 kHz
target halted due to debug-request, current mode: Thread
xPSR: 0xc1000000 pc: 0x0800119c msp: 0x20000da0
adapter speed: 4000 kHz
** Programming Started **
auto erase enabled
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000003a msp: 0x20000da0
wrote 10240 bytes from file cortexm0.elf in 0.817425s (12.234 KiB/s)
** Programming Finished **
adapter speed: 950 kHz
```
For this article, the first time in my life, I converted short video to [animated PNG][9] sequence. Im impressed, goodbye YouTube and sorry IE users. See [apngasm][10] for more info. I should study HTML5 based alternative, but for now, APNG is my preffered way for short looped videos.
![STM32F030F4P6](https://ziutek.github.io/images/mcu/f030-demo-board/blinky.png)
### More Go
If you arent a Go programmer but youve heard something about Go language, you can say: “This syntax is nice, but not a significant improvement over C. Show me  _Go language_ , give mi  _channels_  and  _goroutines!_ ”.
Here you are:
```
import (
"delay"
"stm32/hal/gpio"
"stm32/hal/system"
"stm32/hal/system/timer/systick"
)
var led1, led2 gpio.Pin
func init() {
system.SetupPLL(8, 1, 48/8)
systick.Setup(2e6)
gpio.A.EnableClock(false)
led1 = gpio.A.Pin(4)
led2 = gpio.A.Pin(5)
cfg := &gpio.Config{Mode: gpio.Out, Driver: gpio.OpenDrain}
led1.Setup(cfg)
led2.Setup(cfg)
}
func blinky(led gpio.Pin, period int) {
for {
led.Clear()
delay.Millisec(100)
led.Set()
delay.Millisec(period - 100)
}
}
func main() {
go blinky(led1, 500)
blinky(led2, 1000)
}
```
Code changes are minor: the second LED was added and the previous  _main_  function was renamed to  _blinky_  and now requires two parameters.  _Main_  starts first  _blinky_  in new goroutine, so both LEDs are handled  _concurrently_ . It is worth mentioning that  _gpio.Pin_  type supports concurrent access to different pins of the same GPIO port.
Emgo still has several shortcomings. One of them is that you have to specify a maximum number of goroutines (tasks) in advance. Its time to edit  _script.ld_ :
```
ISRStack = 1024;
MainStack = 1024;
TaskStack = 1024;
MaxTasks = 2;
INCLUDE stm32/f030x4
INCLUDE stm32/loadflash
INCLUDE noos-cortexm
```
The size of the stacks are set by guess, and well not care about them at the moment.
```
$ egc
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
10020 172 172 10364 287c cortexm0.elf
```
Another LED and goroutine costs 248 bytes of Flash.
![STM32F030F4P6](https://ziutek.github.io/images/mcu/f030-demo-board/goroutines.png)
### Channels
Channels are the [preffered way][11] in Go to communicate between goroutines. Emgo goes even further and allows to use  _buffered_  channels by  _interrupt handlers_ . The next example actually shows such case.
```
package main
import (
"delay"
"rtos"
"stm32/hal/gpio"
"stm32/hal/irq"
"stm32/hal/system"
"stm32/hal/system/timer/systick"
"stm32/hal/tim"
)
var (
leds [3]gpio.Pin
timer *tim.Periph
ch = make(chan int, 1)
)
func init() {
system.SetupPLL(8, 1, 48/8)
systick.Setup(2e6)
gpio.A.EnableClock(false)
leds[0] = gpio.A.Pin(4)
leds[1] = gpio.A.Pin(5)
leds[2] = gpio.A.Pin(9)
cfg := &gpio.Config{Mode: gpio.Out, Driver: gpio.OpenDrain}
for _, led := range leds {
led.Set()
led.Setup(cfg)
}
timer = tim.TIM3
pclk := timer.Bus().Clock()
if pclk < system.AHB.Clock() {
pclk *= 2
}
freq := uint(1e3) // Hz
timer.EnableClock(true)
timer.PSC.Store(tim.PSC(pclk/freq - 1))
timer.ARR.Store(700) // ms
timer.DIER.Store(tim.UIE)
timer.CR1.Store(tim.CEN)
rtos.IRQ(irq.TIM3).Enable()
}
func blinky(led gpio.Pin, period int) {
for range ch {
led.Clear()
delay.Millisec(100)
led.Set()
delay.Millisec(period - 100)
}
}
func main() {
go blinky(leds[1], 500)
blinky(leds[2], 500)
}
func timerISR() {
timer.SR.Store(0)
leds[0].Set()
select {
case ch <- 0:
// Success
default:
leds[0].Clear()
}
}
//c:__attribute__((section(".ISRs")))
var ISRs = [...]func(){
irq.TIM3: timerISR,
}
```
Changes compared to the previous example:
1. Thrid LED was added and connected to PA9 pin (TXD pin on UART header).
2. The timer (TIM3) has been introduced as a source of interrupts.
3. The new  _timerISR_  function handles  _irq.TIM3_  interrupt.
4. The new buffered channel with capacity 1 is intended for communication between  _timerISR_  and  _blinky_  goroutines.
5. The  _ISRs_  array acts as  _interrupt vector table_ , a part of bigger  _exception vector table_ .
6. The  _blinkys for statement_  was replaced with a  _range statement_ .
For convenience, all LEDs, or rather their pins, have been collected in the  _leds_  array. Additionally, all pins have been set to a known initial state (high), just before they were configured as outputs.
In this case, we want the timer to tick at 1 kHz. To configure TIM3 prescaler, we need to known its input clock frequency. According to RM the input clock frequency is equal to APBCLK when APBCLK = AHBCLK, otherwise it is equal to 2 x APBCLK.
If the CNT register is incremented at 1 kHz, then the value of ARR register corresponds to the period of counter  _update event_  (reload event) expressed in milliseconds. To make update event to generate interrupts, the UIE bit in DIER register must be set. The CEN bit enables the timer.
Timer peripheral should stay enabled in low-power mode, to keep ticking when the CPU is put to sleep: `timer.EnableClock(true)`. It doesnt matter in case of STM32F0 but its important for code portability.
The  _timerISR_  function handles  _irq.TIM3_  interrupt requests. `timer.SR.Store(0)` clears all event flags in SR register to deassert the IRQ to [NVIC][12]. The rule of thumb is to clear the interrupt flags immedaitely at begining of their handler, because of the IRQ deassert latency. This prevents unjustified re-call the handler again. For absolute certainty, the clear-read sequence should be performed, but in our case, just clearing is enough.
The following code:
```
select {
case ch <- 0:
// Success
default:
leds[0].Clear()
}
```
is a Go way to non-blocking sending on a channel. No one interrupt handler can afford to wait for a free space in the channel. If the channel is full, the default case is taken, and the onboard LED is set on, until the next interrupt.
The  _ISRs_  array contains interrupt vectors. The `//c:__attribute__((section(".ISRs")))` causes that the linker will inserted it into .ISRs section.
The new form of  _blinkys for_  loop:
```
for range ch {
led.Clear()
delay.Millisec(100)
led.Set()
delay.Millisec(period - 100)
}
```
is the equivalent of:
```
for {
_, ok := <-ch
if !ok {
break // Channel closed.
}
led.Clear()
delay.Millisec(100)
led.Set()
delay.Millisec(period - 100)
}
```
Note that in this case we arent interested in the value received from the channel. Were interested only in the fact that there is something to receive. We can give it expression by declaring the channels element type as empty struct `struct{}` instead of  _int_  and send `struct{}{}` values instead of 0, but it can be strange for newcomers eyes.
Lets compile this code:
```
$ egc
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
11096 228 188 11512 2cf8 cortexm0.elf
```
This new example takes 11324 bytes of Flash, 1132 bytes more than the previous one.
With the current timings, both  _blinky_  goroutines consume from the channel much faster than the  _timerISR_  sends to it. So they both wait for new data simultaneously and you can observe the randomness of  _select_ , required by the [Go specification][13].
![STM32F030F4P6](https://ziutek.github.io/images/mcu/f030-demo-board/channels1.png)
The onboard LED is always off, so the channel overrun never occurs.
Lets speed up sending, by changing `timer.ARR.Store(700)` to `timer.ARR.Store(200)`. Now the  _timerISR_ sends 5 messages per second but both recipients together can receive only 4 messages per second.
![STM32F030F4P6](https://ziutek.github.io/images/mcu/f030-demo-board/channels2.png)
As you can see, the  _timerISR_  lights the yellow LED which means there is no space in the channel.
This is where I finish the first part of this article. You should know that this part didnt show you the most important thing in Go language,  _interfaces_ .
Goroutines and channels are only nice and convenient syntax. You can replace them with your own code - not easy but feasible. Interfaces are the essence of Go, and thats what I will start with in the [second part][14] of this article.
We still have some free space on Flash.
--------------------------------------------------------------------------------
via: https://ziutek.github.io/2018/03/30/go_on_very_small_hardware.html
作者:[ Michał Derkacz][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://ziutek.github.io/
[1]:https://en.wikipedia.org/wiki/ARM_Cortex-M#Cortex-M0
[2]:https://ziutek.github.io/2018/03/30/go_on_very_small_hardware.html
[3]:http://www.st.com/content/st_com/en/products/microcontrollers/stm32-32-bit-arm-cortex-mcus/stm32-mainstream-mcus/stm32f0-series/stm32f0x0-value-line/stm32f030f4.html
[4]:https://golang.org/
[5]:https://github.com/ziutek/emgo
[6]:https://github.com/ziutek/emgo/tree/master/egpath/src/stm32/hal
[7]:http://www.st.com/resource/en/reference_manual/dm00091010.pdf
[8]:https://github.com/ziutek/emgo
[9]:https://en.wikipedia.org/wiki/APNG
[10]:http://apngasm.sourceforge.net/
[11]:https://blog.golang.org/share-memory-by-communicating
[12]:http://infocenter.arm.com/help/topic/com.arm.doc.ddi0432c/Cihbecee.html
[13]:https://golang.org/ref/spec#Select_statements
[14]:https://ziutek.github.io/2018/04/14/go_on_very_small_hardware2.html

View File

@ -1,5 +1,5 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: translator: (heguangzhi)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
@ -232,7 +232,7 @@ via: https://www.linuxtechi.com/configure-static-ip-address-rhel8/
作者:[Pradeep Kumar][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
译者:[heguangzhi](https://github.com/heguangzhi)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -1,232 +0,0 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Getting started with Zsh)
[#]: via: (https://opensource.com/article/19/9/getting-started-zsh)
[#]: author: (Seth Kenlon https://opensource.com/users/sethhttps://opensource.com/users/sethhttps://opensource.com/users/sethhttps://opensource.com/users/sethhttps://opensource.com/users/falm)
Getting started with Zsh
======
Improve your shell game by upgrading from Bash to Z-shell.
![bash logo on green background][1]
Z-shell (or Zsh) is an interactive Bourne-like POSIX shell known for its abundance of innovative features. Z-Shell users often cite its many conveniences and credit it for increased efficiency and extensive customization.
If you're relatively new to Linux or Unix but experienced enough to have opened a terminal and run a few commands, you have probably used the Bash shell. Bash is arguably the definitive free software shell, partly because of its progressive features and partly because it ships as the default shell on most of the popular Linux and Unix operating systems. However, the more you use a shell, the more you start to find small things that might be better for the way you want to use it. If there's one thing open source is famous for, it's _choice_. Many people choose to "graduate" from Bash to Z.
### What is Zsh?
A shell is just an interface to your operating system. An interactive shell allows you to type in commands through what is called _standard input_, or **stdin**, and get output through _standard output_ and _standard error_, or **stdout** and **stderr**. There are many shells, including Bash, Csh, Ksh, Tcsh, Dash, and Zsh. Each has features based on what its programmers thought would be best for a shell. Whether those features are good or bad is up to you, the end user.
Zsh has features like interactive Tab completion, automated file searching, regex integration, advanced shorthand for defining command scope, and a rich theme engine. These features are included in an otherwise familiar Bourne-like shell environment, meaning that if you already know and love Bash, you'll find Zsh familiar—except with more features. You might think of it as a kind of Bash++.
### Installing Zsh
Install Zsh with your package manager.
On Fedora, RHEL, and CentOS:
```
`$ sudo dnf install zsh`
```
On Ubuntu and Debian:
```
`$ sudo apt install zsh`
```
On MacOS, you can install it using MacPorts:
```
`$ sudo port install zsh`
```
Or with Homebrew:
```
`$ brew install zsh`
```
It's possible to run Zsh on Windows, but only on top of a Linux or Linux-like layer such as [Windows Subsystem for Linux][2] (WSL) or [Cygwin][3]. That installation is out of scope for this article, so refer to Microsoft documentation.
### Setting up Zsh
Zsh is not a terminal emulator; it's a shell that runs inside a terminal emulator. So, to launch Zsh, you must first launch a terminal window such as GNOME Terminal, Konsole, Terminal, iTerm2, rxvt, or another terminal of your preference. Then you can launch Zsh by typing:
```
`$ zsh`
```
The first time you launch Zsh, you're asked to choose some configuration options. These can all be changed later, so press **1** to continue.
```
This is the Z Shell configuration function for new users, zsh-newuser-install.
(q)  Quit and do nothing.
(0)  Exit, creating the file ~/.zshrc
(1)  Continue to the main menu.
```
There are four categories of preferences, so just start at the top.
1. The first category lets you choose how many commands are retained in your shell history file. By default, it's set to 1,000 lines.
2. Zsh completion is one of its most exciting features. To keep things simple, consider activating it with its default options until you get used to how it works. Press **1** for default options, **2** to set options manually.
3. Choose Emacs or Vi key bindings. Bash uses Emacs bindings, so you may be used to that already.
4. Finally, you can learn about (and set or unset) some of Zsh's subtle features. For instance, you can stop using the **cd** command by allowing Zsh to initiate a directory change when you provide a non-executable path with no command. To activate one of these extra options, type the option number and enter **s** to _set_ it. Try turning on all options to get the full Zsh experience. You can unset them later by editing **~/.zshrc**.
To complete configuration, press **0**.
### Using Zsh
At first, Zsh feels a lot like using Bash, which is unmistakably one of its many features. There are serious differences between, for instance, Bash and Tcsh, so being able to switch between Bash and Zsh is a convenience that makes Zsh easy to try and easy to use at home if you have to use Bash at work or on your server.
#### Change directory with Zsh
It's the small differences that make Zsh nice. First, try changing the directory to your Documents folder _without the **cd** command_. It seems too good to be true; but if you enter a directory path with no further instruction, Zsh changes to that directory:
```
% Documents
% pwd
/home/seth/Documents
```
That renders an error in Bash or any other normal shell. But Zsh is far from normal, and this is just the beginning.
#### Search with Zsh
When you want to find a file using a normal shell, you probably resort to the **find** or **locate** command. At the very least, you may have used **ls -R** for a recursive listing of a set of directories. Zsh has a built-in feature allowing it to find a file in the current or any other subdirectory.
For instance, assume you have two files called **foo.txt**. One is located in your current directory, and the other is in a subdirectory called **foo**. In a Bash shell, you can list the file in the current directory with:
```
$ ls
foo.txt
```
and you can list the other one by stating the subdirectory's path explicitly:
```
$ ls foo
foo.txt
```
To list both, you must use the **-R** switch, maybe combined with **grep**:
```
$ ls -R | grep foo.txt
foo.txt
foo.txt
```
But in Zsh, you can use the ****** shorthand:
```
% ls **/foo.txt
foo.txt
foo.txt
```
And you can use this syntax with any command, not just with **ls**. Imagine your increased efficiency when moving specific file types from one collection of directories to a single location, or concatenating snippets of text into a file, or grepping through logs.
### Using Zsh Tab completion
Tab completion is a power-user feature in Bash and some other shells, and it took the Unix world by storm when it became commonplace. No longer did Unix users have to resort to wildcards when typing long and tedious paths (such as **/h*/s*h/V*/SCS/sc*/comp*/t*/a*/*9/04/LS*boat*v**, which is a lot easier than typing **/home/seth/Videos/SCS/scenes/composite/takes/approved/109/04/LS_boat-port-cargo-mover.mkv**). Instead, they could just press the Tab key when they entered enough of a unique string. For example, if you know there's only one directory starting with an **h** at the root level of your system, you might type **/h** and then hit Tab. It's fast, it's simple, it's efficient. It also confirms a path exists; if Tab doesn't complete anything, you know you're looking in the wrong place or you mistyped part of the path.
However, if you have many directories that share five or more of the same first letters, Tab staunchly refuses to complete. While in most modern terminals it will (at least) reveal the files blocking it from guessing what you mean, it usually takes two Tab presses to reveal them; therefore, Tab completion often becomes such an interplay of letters and Tabs across your keyboard that you feel like you're training for a piano recital.
Zsh solves this minor annoyance by cycling through possible completions. If you type **ls ~/D** and press Tab, Zsh completes your command with **Documents** first; if you press Tab again, it offers **Downloads**, and so on until you find the one you want.
### Wildcards in Zsh
Wildcards behave differently in Zsh than what Bash users are used to. First of all, they can be modified. For example, if you want to list all folders in your current directory, you can use a modified wildcard:
```
% ls
dir0   dir1   dir2   file0   file1
% ls *(/)
dir0   dir1   dir2
```
In this example, the **(/)** qualifies the results of the wildcard so Zsh will display only directories. To list just the files, use **(.)**. To list symlinks, use **(@)**. To list executable files, use **(*)**.
```
% ls ~/bin/*(*)
fop  exify  tt
```
Zsh isn't aware of file types only. It can also list according to modification time, using the same wildcard modifier convention. For example, if you want to find a file that was modified within the past eight hours, use the **mh** modifier (for **modified** and **hours**) and the negative integer of hours:
```
% ls ~/Documents/*(mh-8)
cal.org   game.org   home.org
```
To find a file modified more than (for instance) two days ago, the modifiers change to **md** (for **modified** and **day**) with a positive integer:
```
% ls ~/Documents/*(+2)
holiday.org
```
There's a lot more you can do with wildcard modifiers and qualifiers, so read the [Zsh man page][4] for full details.
#### The wildcard side effect
To use wildcards the way you would use them in Bash, sometimes they must be escaped in Zsh. For instance, if you're copying some files to your server in Bash, you might use a wildcard like this:
```
`$ scp IMG_*.JPG seth@example.com:~/www/ph*/*19/09/14`
```
That works in Bash, but Zsh returns an error because it tries to expand the variables on the remote side before issuing the **scp** command. To avoid this, you must escape the remote variables:
```
`% scp IMG_*.JPG seth@example.com:~/www/ph\*/\*19/09/14`
```
It's these types of little exceptions that can frustrate you when you're switching to a new shell. There aren't many when using Zsh (there are probably more when switching back to Bash after experiencing Zsh) but when they happen, remain calm and be explicit. Rarely will you go wrong to adhere strictly to POSIX—but if that fails, look up the problem to solve it and move on. [Hyperpolyglot.org][5] has proven invaluable to many users stuck on one shell at work and another at home.
In my next Zsh article, I'll show you how to install themes and plugins to make your Z-Shell even Z-ier.
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/9/getting-started-zsh
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/sethhttps://opensource.com/users/sethhttps://opensource.com/users/sethhttps://opensource.com/users/sethhttps://opensource.com/users/falm
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/bash_command_line.png?itok=k4z94W2U (bash logo on green background)
[2]: https://devblogs.microsoft.com/commandline/category/bash-on-ubuntu-on-windows/
[3]: https://www.cygwin.com/
[4]: https://linux.die.net/man/1/zsh
[5]: http://hyperpolyglot.org/unix-shells

View File

@ -0,0 +1,510 @@
Go语言在极小硬件上的运用第一部分
============================================================
_Go_ 语言,能在多低下的配置上运行并发挥作用呢?
我最近购买了一个特别便宜的开发板:
[![STM32F030F4P6](https://ziutek.github.io/images/mcu/f030-demo-board/board.jpg)][2]
我购买它的理由有三个。首先作为程序员从未接触过STM320系列的开发板。其次 STM32F10x系列使用频率也在降低。STM320系列的MCU很便宜有更新的外设对系列产品进行了改进问题修复也做得更好了。最后为了这篇文章我选用了这一系列中最低配置的开发板整件事情就变得有趣起来了。
### 硬件部分
[STM32F030F4P6][3] 给人留下了很深的印象:
* CPU: [Cortex M0][1] 48 MHz (最低配置只有12000个逻辑门电路),
* RAM: 4 KB,
* Flash: 16 KB,
* ADC, SPI, I2C, USART 和几个定时器,
以上这些采用了TSSOP20封装。正如你所见这是一个很小的32位系统。
### 软件部分
如果你想知道如何在这块开发板上使用 [Go][4] 编程你需要反复阅读硬件手册。真实情况是有人在Go 编译器中给Cortex-M0提供支持可能性很小。而且这还仅仅只是第一个要解决的问题。
我会使用[Emgo][5]但别担心之后你会看到它如何让Go在如此小的系统上尽可能发挥作用。
在我拿到这块开发板之前,对 [stm32/hal][6] 系列下的F0 MCU 没有任何支持。在简单研究 [参考手册][7]后,我发现 STM32F0系列是STM32F3的一个基础这让在新端口上开发的工作变得容易了一些。
如果你想接着本文的步骤做下去需要先安装Emgo
```
cd $HOME
git clone https://github.com/ziutek/emgo/
cd emgo/egc
go install
```
然后设置一下环境变量
```
export EGCC=path_to_arm_gcc # eg. /usr/local/arm/bin/arm-none-eabi-gcc
export EGLD=path_to_arm_linker # eg. /usr/local/arm/bin/arm-none-eabi-ld
export EGAR=path_to_arm_archiver # eg. /usr/local/arm/bin/arm-none-eabi-ar
export EGROOT=$HOME/emgo/egroot
export EGPATH=$HOME/emgo/egpath
export EGARCH=cortexm0
export EGOS=noos
export EGTARGET=f030x6
```
更详细的说明可以在 [Emgo][8]官网上找到。
要确保 egc 在你的PATH 中。 你可以使用 `go build` 来代替 `go install`,然后把 egc 复制到你的 _$HOME/bin__/usr/local/bin_ 中。
现在为你的第一个Emgo程序创建一个新文件夹随后把示例中链接器脚本复制过来
```
mkdir $HOME/firstemgo
cd $HOME/firstemgo
cp $EGPATH/src/stm32/examples/f030-demo-board/blinky/script.ld .
```
### 最基本程序
_main.go_ 文件中创建一个最基本的程序:
```
package main
func main() {
}
```
文件编译没有出现任何问题:
```
$ egc
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
7452 172 104 7728 1e30 cortexm0.elf
```
第一次编译可能会花点时间。编译后产生的二进制占用了7624个字节的Flash空间文本+数据。对于一个什么都没做的程序来说占用的空间有些大。还剩下8760字节可以用来做些有用的事。
不妨试试传统的 _Hello, World!_ 程序:
```
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
```
不幸的是,这次结果有些糟糕:
```
$ egc
/usr/local/arm/bin/arm-none-eabi-ld: /home/michal/P/go/src/github.com/ziutek/emgo/egpath/src/stm32/examples/f030-demo-board/blog/cortexm0.elf section `.text' will not fit in region `Flash'
/usr/local/arm/bin/arm-none-eabi-ld: region `Flash' overflowed by 10880 bytes
exit status 1
```
_Hello, World!_ 需要 STM32F030x6 上至少32KB的Flash空间.
_fmt_ 包强制包含整个 _strconv__reflect_ 包。这三个包即使在精简版本中的Emgo中占用空间也很大。我们不能使用这个例子了。有很多的应用不需要好看的文本输出。通常一个或多个LED或者七段数码管显示就足够了。不过在第二部分我会尝试使用 _strconv_ 包来格式化并在UART 上显示一些数字和文本。
### 闪烁
我们的开发板上有一个与PA4引脚和 VCC 相连的LED。这次我们的代码稍稍长了一些
```
package main
import (
"delay"
"stm32/hal/gpio"
"stm32/hal/system"
"stm32/hal/system/timer/systick"
)
var led gpio.Pin
func init() {
system.SetupPLL(8, 1, 48/8)
systick.Setup(2e6)
gpio.A.EnableClock(false)
led = gpio.A.Pin(4)
cfg := &gpio.Config{Mode: gpio.Out, Driver: gpio.OpenDrain}
led.Setup(cfg)
}
func main() {
for {
led.Clear()
delay.Millisec(100)
led.Set()
delay.Millisec(900)
}
}
```
按照惯例, _init_ 函数用来初始化和配置外设。
`system.SetupPLL(8, 1, 48/8)` 用来配置RCC将外部的8 MHz振荡器的PLL作为系统时钟源。PLL 分频器设置为1倍频数设置为 48/8 =6这样系统时钟频率为48MHz.
`systick.Setup(2e6)` 将 Cortex-M SYSTICK 时钟作为系统时钟,每隔 2e6次纳秒运行一次每秒钟500次
`gpio.A.EnableClock(false)` 开启了 GPIO A 口的时钟。_False_ 意味着这一时钟在低功耗模式下会被禁用但在STM32F0系列中并未实现这一功能。
`led.Setup(cfg)` 设置 PA4 引脚为开漏输出.
`led.Clear()` 将 PA4引脚设为低, 在开漏设置中打开LED.
`led.Set()` 将 PA4 设为高电平状态 , 关掉LED.
编译这个代码:
```
$ egc
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
9772 172 168 10112 2780 cortexm0.elf
```
正如你所看到的闪烁占用了2320 字节比最基本程序占用空间要大。还有6440字节的剩余空间。
看看代码是否能运行:
```
$ openocd -d0 -f interface/stlink.cfg -f target/stm32f0x.cfg -c 'init; program cortexm0.elf; reset run; exit'
Open On-Chip Debugger 0.10.0+dev-00319-g8f1f912a (2018-03-07-19:20)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
debug_level: 0
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
none separate
adapter speed: 950 kHz
target halted due to debug-request, current mode: Thread
xPSR: 0xc1000000 pc: 0x0800119c msp: 0x20000da0
adapter speed: 4000 kHz
** Programming Started **
auto erase enabled
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000003a msp: 0x20000da0
wrote 10240 bytes from file cortexm0.elf in 0.817425s (12.234 KiB/s)
** Programming Finished **
adapter speed: 950 kHz
```
在这篇文章中,这是我第一次,将一个短视频转换成[动画PNG][9]。我对此印象很深,再见了 YouTube. 对于IE用户我很抱歉更多信息请看[apngasm][10].我本应该学习 HTML5但现在APNG是我最喜欢的用来播放循环短视频的方法了。
![STM32F030F4P6](https://ziutek.github.io/images/mcu/f030-demo-board/blinky.png)
### 更多的Go语言编程
如果你不是一个Go 程序员但你已经听说过一些关于Go 语言的事情你可能会说“Go语法很好但跟C比起来并没有明显的提升.让我看看 _Go 语言__channels_ 和 _goroutines!”
接下来我会一一展示:
```
import (
"delay"
"stm32/hal/gpio"
"stm32/hal/system"
"stm32/hal/system/timer/systick"
)
var led1, led2 gpio.Pin
func init() {
system.SetupPLL(8, 1, 48/8)
systick.Setup(2e6)
gpio.A.EnableClock(false)
led1 = gpio.A.Pin(4)
led2 = gpio.A.Pin(5)
cfg := &gpio.Config{Mode: gpio.Out, Driver: gpio.OpenDrain}
led1.Setup(cfg)
led2.Setup(cfg)
}
func blinky(led gpio.Pin, period int) {
for {
led.Clear()
delay.Millisec(100)
led.Set()
delay.Millisec(period - 100)
}
}
func main() {
go blinky(led1, 500)
blinky(led2, 1000)
}
```
代码改动很小: 添加了第二个LED上一个例子中的 _main_ 函数被重命名为 _blinky_ 并且需要提供两个参数. _Main_ 在新的goroutine 中先调用 _blinky_, 所以两个LED灯在并行使用. 值得一提的是, _gpio.Pin_ 可以同时访问同一GPIO口的不同引脚。
Emgo 还有很多不足。其中之一就是你需要提前规定goroutines(tasks)的最大执行数量.是时候修改 _script.ld_ 了:
```
ISRStack = 1024;
MainStack = 1024;
TaskStack = 1024;
MaxTasks = 2;
INCLUDE stm32/f030x4
INCLUDE stm32/loadflash
INCLUDE noos-cortexm
```
栈的大小需要靠猜,现在还不用关心这一点。
```
$ egc
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
10020 172 172 10364 287c cortexm0.elf
```
另一个LED 和 goroutine 一共占用了248字节的Flash空间.
![STM32F030F4P6](https://ziutek.github.io/images/mcu/f030-demo-board/goroutines.png)
### Channels
Channels 是Go语言中goroutines之间相互通信的一种[推荐方式][11].Emgo 甚至能允许通过 _中断处理_ 来使用缓冲channel. 下一个例子就展示了这种情况.
```
package main
import (
"delay"
"rtos"
"stm32/hal/gpio"
"stm32/hal/irq"
"stm32/hal/system"
"stm32/hal/system/timer/systick"
"stm32/hal/tim"
)
var (
leds [3]gpio.Pin
timer *tim.Periph
ch = make(chan int, 1)
)
func init() {
system.SetupPLL(8, 1, 48/8)
systick.Setup(2e6)
gpio.A.EnableClock(false)
leds[0] = gpio.A.Pin(4)
leds[1] = gpio.A.Pin(5)
leds[2] = gpio.A.Pin(9)
cfg := &gpio.Config{Mode: gpio.Out, Driver: gpio.OpenDrain}
for _, led := range leds {
led.Set()
led.Setup(cfg)
}
timer = tim.TIM3
pclk := timer.Bus().Clock()
if pclk < system.AHB.Clock() {
pclk *= 2
}
freq := uint(1e3) // Hz
timer.EnableClock(true)
timer.PSC.Store(tim.PSC(pclk/freq - 1))
timer.ARR.Store(700) // ms
timer.DIER.Store(tim.UIE)
timer.CR1.Store(tim.CEN)
rtos.IRQ(irq.TIM3).Enable()
}
func blinky(led gpio.Pin, period int) {
for range ch {
led.Clear()
delay.Millisec(100)
led.Set()
delay.Millisec(period - 100)
}
}
func main() {
go blinky(leds[1], 500)
blinky(leds[2], 500)
}
func timerISR() {
timer.SR.Store(0)
leds[0].Set()
select {
case ch <- 0:
// Success
default:
leds[0].Clear()
}
}
//c:__attribute__((section(".ISRs")))
var ISRs = [...]func(){
irq.TIM3: timerISR,
}
```
与之前例子相比较下的不同:
1. 添加了第三个LED并连接到 PA9 引脚.UART头的TXD引脚
2. 时钟TIM3作为中断源.
3. 新函数 _timerISR_ 用来处理 _irq.TIM3_ 的中断.
4. 新增容量为1 的缓冲channel 是为了 _timerISR__blinky_ goroutines 之间的通信.
5. _ISRs_ 数组作为 _中断向量表_,是 更大的_异常向量表_ 的一部分.
6. _blinky中的for语句_ 被替换成 _range语句_ .
为了方便起见所有的LED或者说他们的引脚都被放在 _leds_ 这个数组里. 另外, 所有引脚在被配置为输出之前,都设置为一种已知的初始状态(高电平状态).
在这个例子里我们想让时钟以1 kHz的频率运行。为了配置预分频器我们需要知道它的输入时钟频率。通过参考手册我们知道输入时钟频率在APBCLK = AHBCLK时,与APBCLK 相同反之等于2倍的APBCLK。
如果CNT寄存器增加 1kHz,那么ARR寄存器的值等于 _更新事件_ (重载事件)在毫秒中的计数周期。 为了让更新事件产生中断必须要设置DIER 寄存器中的UIE位。CEN位能启动时钟。
时钟外设在低功耗模式下必须启用为了自身能在CPU处于休眠时保持运行: `timer.EnableClock(true)`。这在STM32F0中无关紧要但对代码可移植性却十分重要。
_timerISR_ 函数处理 _irq.TIM3_ 的中断请求。 `timer.SR.Store(0)` 会清除SR寄存器里的所有事件标志无效化向[NVIC][12]发出的所有中断请求。凭借经验,由于中断请求无效的延时性,需要在程序一开始马上清除所有的中断标志。这避免了无意间再次调用处理。为了确保万无一失,需要先清除标志,再读取,但是在我们的例子中,清除标志就已经足够了。
下面的这几行代码:
```
select {
case ch <- 0:
// Success
default:
leds[0].Clear()
}
```
是Go语言中如何在channel 上非阻塞地发送消息的方法。 中断处理程序无法一直等待channel 中的空余空间。如果channel已满则执行default,开发板上的LED就会开启直到下一次中断。
_ISRs_ 数组包含了中断向量表。 `//c:__attribute__((section(".ISRs")))` 会导致链接器将数组插入到 .ISRs section 中。
_blinkys for_ 循环的新写法:
```
for range ch {
led.Clear()
delay.Millisec(100)
led.Set()
delay.Millisec(period - 100)
}
```
等价于:
```
for {
_, ok := <-ch
if !ok {
break // Channel closed.
}
led.Clear()
delay.Millisec(100)
led.Set()
delay.Millisec(period - 100)
}
```
注意在这个例子中我们不在意channel中收到的值我们只对其接受到的消息感兴趣。我们可以在声明时将channel元素类型中的 _int_ 用空结构体来代替,发送消息时, 用`struct{}{}` 结构体的值代替0但这部分对新手来说可能会有些陌生。
让我们来编译一下代码:
```
$ egc
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
11096 228 188 11512 2cf8 cortexm0.elf
```
新的例子占用了11324字节的Flash 空间比上一个例子多占用了1132字节。
采用现在的时序,两个 _blinky_ goroutines 从channel 中获取数据的速度,比 _timerISR_ 发送数据的速度要快。所以它们在同时等待新数据,你还能观察到 _select_ 的随机性,这也是[Go 规范][13]所要求的.
![STM32F030F4P6](https://ziutek.github.io/images/mcu/f030-demo-board/channels1.png)
开发板上的LED一直没有亮起说明channel 从未出现过溢出。
我们可以加快消息发送的速度,将 `timer.ARR.Store(700)` 改为 `timer.ARR.Store(200)`。 现在 _timerISR_ 每秒钟发送5条消息但是两个接收者加起来每秒也只能接受4条消息。
![STM32F030F4P6](https://ziutek.github.io/images/mcu/f030-demo-board/channels2.png)
正如你所看到的, _timerISR_ 开启黄色LED灯意味着 channel 上已经没有剩余空间了。
第一部分到这里就结束了。你应该知道这一部分并未展示Go中最重要的部分 _接口_.
Goroutine 和channel 只是一些方便好用的语法。你可以用自己的代码来替换它们,这并不容易,但也可以实现。 接口是Go 语言的基础。这是文章中 [第二部分][14]所要提到的.
在Flash上我们还有些剩余空间.
--------------------------------------------------------------------------------
via: https://ziutek.github.io/2018/03/30/go_on_very_small_hardware.html
作者:[ Michał Derkacz][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://ziutek.github.io/
[1]:https://en.wikipedia.org/wiki/ARM_Cortex-M#Cortex-M0
[2]:https://ziutek.github.io/2018/03/30/go_on_very_small_hardware.html
[3]:http://www.st.com/content/st_com/en/products/microcontrollers/stm32-32-bit-arm-cortex-mcus/stm32-mainstream-mcus/stm32f0-series/stm32f0x0-value-line/stm32f030f4.html
[4]:https://golang.org/
[5]:https://github.com/ziutek/emgo
[6]:https://github.com/ziutek/emgo/tree/master/egpath/src/stm32/hal
[7]:http://www.st.com/resource/en/reference_manual/dm00091010.pdf
[8]:https://github.com/ziutek/emgo
[9]:https://en.wikipedia.org/wiki/APNG
[10]:http://apngasm.sourceforge.net/
[11]:https://blog.golang.org/share-memory-by-communicating
[12]:http://infocenter.arm.com/help/topic/com.arm.doc.ddi0432c/Cihbecee.html
[13]:https://golang.org/ref/spec#Select_statements
[14]:https://ziutek.github.io/2018/04/14/go_on_very_small_hardware2.html