ATtiny88初体验(三):串口¶
ATtiny88单片机不包含串口模块,因此只能使用软件方式模拟串口时序。
串口通信时序通常由起始位、数据位、校验位和停止位四个部分组成,常见的配置为1位起始位、8位数据位、无校验位和1位停止位。
模拟串口发送时序¶
- 设置TX引脚为输出模式,初始电平状态为高电平。
- 设置定时器周期,以9600波特率为例,将定时器周期设为 \(\frac{1s}{9600} \approx 104us\) 。
- TX引脚输出低电平(起始位),同时开启定时器。
- 之后的8次定时器中断,每次输出1位数据,从低位开始。
- 第9次定时器中断,TX引脚输出高电平(停止位)。
- 第10次定时器中断,关闭定时器。
模拟串口接收时序¶
- 设置RX引脚为输入模式,使能上拉电阻,开启下降沿中断。
- 当接收到起始位时,触发下降沿中断,设置定时器周期为 \(\frac{1s}{9600} \times \frac{1}{6} \approx 17us\) ,开启定时器。
- 之后的30次定时器中断,对RX引脚的电平状态进行计数(起始位)。
- 第1次定时器中断,将定时器周期重设为 \(\frac{1s}{9600} \times \frac{1}{3} \approx 35us\) 。
- 第3次定时器中断,如果高电平数量大于低电平数量,则表示起始位接收失败,直接关闭定时器,并开启下降沿中断。
- 第6/9/.../24/27次定时器中断,判断高电平和低电平的数量,选取数量多的那个电平作为数据位,从低位开始填充。
- 第30次定时器中断,关闭定时器中断,开启下降沿中断,如果高电平数量大于低电平数量,则表示成功接收到停止位,数据有效。
外部中断¶
ATtiny88有8个外部中断源:INT0、INT1、PCI0、PCI1、PCI2、PCI3。其中INT0/1支持低电平/下降沿/上升沿触发,PCI0/1/2/3在引脚状态改变时触发。
ATtiny88外部中断和引脚的对应关系如下:
中断源 | 引脚 |
---|---|
INT0 | PD2 |
INT1 | PD3 |
PCI0 | PB[0:7] -> PCINT[0:7] |
PCI1 | PC[0:7] -> PCINT[8:15] |
PCI2 | PD[0:7] -> PCINT[16:23] |
PCI3 | PA[0:3] -> PCINT[24:27] |
注意:即使引脚配置为输出模式,也能触发相应的中断。
寄存器¶
ISC1[1:0]
:设置INT1中断触发方式。ISC0[1:0]
:设置INT0中断触发方式,取值同ISC1[1:0]
。
INT1
:设为1使能INT1中断。INT0
:设为1使能INT0中断。
INTF1
:INT1中断标志位,执行中断函数时自动清零,也可以写1清零。INTF0
:INT0中断标志位,执行中断函数时自动清零,也可以写1清零。
PCIE3
:设为1使能PCI3(PCINT[27:24])中断。PCIE2
:设为1使能PCI2(PCINT[23:16])中断。PCIE1
:设为1使能PCI1(PCINT[15:8])中断。PCIE0
:设为1使能PCI0(PCINT[7:0])中断。
PCIF3
:PCI3(PCINT[27:24])中断标志位,执行中断函数时自动清零,也可以写1清零。PCIF2
:PCI2(PCINT[23:16])中断标志位,执行中断函数时自动清零,也可以写1清零。PCIF1
:PCI1(PCINT[15:8])中断标志位,执行中断函数时自动清零,也可以写1清零。PCIF0
:PCI0(PCINT[7:0])中断标志位,执行中断函数时自动清零,也可以写1清零。
PCINTx
:设为1使能PCINTx中断。
代码实现¶
代码文件的整体结构如下:
inc/serial.h
头文件的代码内容如下:
src/serial.c
源文件的代码内容如下,其中将PD1引脚定义为TX,将PD2引脚定义为RX:
src/serial.c | |
---|---|
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 |
|
注意:实测115200以下(含)的波特率发送都正常,但是9600以上(不含)的波特率接收不正常,建议日常使用9600波特率。
重定向stdio到串口¶
为了更方便的使用串口,可以将标准输入输出重定向到串口,在AVR GCC中的做法如下:
- 定义输入和输出的接口函数,原型如下:
- 使用
FDEV_SETUP_STREAM
创建一个stream。 - 将上面创建的stream替换掉
stdout
/stdin
。
代码实现¶
src/main.c
源文件的代码内容如下: