Go 语言在极小硬件上的运用(二)( 三 )


> 00000062 T stm32$hal$usart$Driver$DisableRx> 00000072 T stm32$hal$usart$Driver$RxDMAISR> 00000076 T internal$Type$Implements> 00000080 T stm32$hal$usart$Driver$EnableRx> 00000084 t errors$New> 00000096 R $8$stm32$hal$usart$Driver$$> 00000100 T stm32$hal$usart$Error$Error> 00000360 T io$WriteString> 00000660 T stm32$hal$usart$Driver$Read因此 , 即使我们不使用 usart.Driver.Read 方法 , 但它被编译进来了 , 与 DisableRx、RxDMAISR、EnableRx 以及上面未提及的其他方法一样 。 不幸的是 , 如果你为接口赋值了一些内容 , 就需要它的完整方法集(包含所有依赖项) 。 对于使用大多数方法的大型程序来说 , 这不是问题 。 但是对于我们这种极简的情况而言 , 这是一个巨大的负担 。
我们已经接近 MCU 的极限 , 但让我们尝试打印一些数字(你需要在 import 部分中用 strconv 替换 io 包):
func main() {a := 12b := -123tts.WriteString("a = ")strconv.WriteInt(tts, a, 10, 0, 0)tts.WriteString("\r\n")tts.WriteString("b = ")strconv.WriteInt(tts, b, 10, 0, 0)tts.WriteString("\r\n")tts.WriteString("hex(a) = ")strconv.WriteInt(tts, a, 16, 0, 0)tts.WriteString("\r\n")tts.WriteString("hex(b) = ")strconv.WriteInt(tts, b, 16, 0, 0)tts.WriteString("\r\n")}与使用 io.WriteString 函数的情况一样 , strconv.WriteInt 的第一个参数的类型为 io.Writer 。
$ egc/usr/local/arm/bin/arm-none-eabi-ld: /home/michal/firstemgo/cortexm0.elf section `.rodata' will not fit in region `Flash'/usr/local/arm/bin/arm-none-eabi-ld: region `Flash' overflowed by 692 bytesexit status 1这一次我们的空间超出的不多 。 让我们试着精简一下有关类型的信息:
$ cd $HOME/emgo$ ./clean.sh$ cd $HOME/firstemgo$ egc -nf -nt$ arm-none-eabi-size cortexm0.elftextdatabssdechex filename15876316320165124080 cortexm0.elf很接近 , 但很合适 。 让我们加载并运行此代码:
a = 12b = -123hex(a) = chex(b) = -7bEmgo 中的 strconv 包与 Go 中的原型有很大的不同 。 它旨在直接用于写入格式化的数字 , 并且在许多情况下可以替换沉重的 fmt 包 。这就是为什么函数名称以 Write 而不是 Format 开头 , 并具有额外的两个参数的原因 。以下是其用法示例:
func main() {b := -123strconv.WriteInt(tts, b, 10, 0, 0)tts.WriteString("\r\n")strconv.WriteInt(tts, b, 10, 6, ' ')tts.WriteString("\r\n")strconv.WriteInt(tts, b, 10, 6, '0')tts.WriteString("\r\n")strconv.WriteInt(tts, b, 10, 6, '.')tts.WriteString("\r\n")strconv.WriteInt(tts, b, 10, -6, ' ')tts.WriteString("\r\n")strconv.WriteInt(tts, b, 10, -6, '0')tts.WriteString("\r\n")strconv.WriteInt(tts, b, 10, -6, '.')tts.WriteString("\r\n")}下面是它的输出:
-123-123-00123..-123-123-123-123..Unix 流 和 莫尔斯电码(Morse code)由于大多数写入的函数都使用 io.Writer 而不是具体类型(例如 C 中的 FILE ) , 因此我们获得了类似于 Unix 流(stream) 的功能 。 在 Unix 中 , 我们可以轻松地组合简单的命令来执行更大的任务 。 例如 , 我们可以通过以下方式将文本写入文件:
echo "Hello, World!" > file.txt【Go 语言在极小硬件上的运用(二)】> 操作符将前面命令的输出流写入文件 。 还有 | 操作符 , 用于连接相邻命令的输出流和输入流 。
多亏了流 , 我们可以轻松地转换/过滤任何命令的输出 。 例如 , 要将所有字母转换为大写 , 我们可以通过 tr 命令过滤 echo 的输出:
echo "Hello, World!" | tr a-z A-Z > file.txt为了显示 io.Writer 和 Unix 流之间的类比 , 让我们编写以下代码:
io.WriteString(tts, "Hello, World!\r\n")采用以下伪 unix 形式:
io.WriteString "Hello, World!" | usart.Driver usart.USART1下一个示例将显示如何执行此操作:
io.WriteString "Hello, World!" | MorseWriter | usart.Driver usart.USART1让我们来创建一个简单的编码器 , 它使用莫尔斯电码对写入的文本进行编码:
type MorseWriter struct {W io.Writer}func (w *MorseWriter) Write(s []byte) (int, error) {var buf [8]bytefor n, c := range s {switch {case c == '\n':c = ' ' // Replace new lines with spaces.case 'a' <= ci < uint(symbol.length); i++ {if (symbol.code>>i) err != nil {return n, err}}return len(s), nil}type morseSymbol struct {code, length byte}//emgo:constvar morseSymbols = [...]morseSymbol{{1<<0 | 1<<1 | 1<<2, 4}, // ! ---.{1<<1 | 1<<4, 6},// " .-..-.{},// #{1<<3 | 1<<6, 7},// $ ...-..-// Some code omitted...{1<<0 | 1<<3, 4},// X -..-{1<<0 | 1<<2 | 1<<3, 4}, // Y -.--{1<<0 | 1<<1, 4},// Z --..}你可以在 这里 找到完整的 morseSymbols 数组 。//emgo:const 指令确保 morseSymbols 数组不会被复制到 RAM 中 。
现在我们可以通过两种方式打印句子: