ARM单片机自学指南与笔记分享

GPIO

GPIO的输出速度指的是电平翻转所需的时间


推挽输出:两个mos管同一时刻只有一个导通(两种状态一推一挽)输出一高一低
设置推挽输出后仍可以通过读取输出/输入状态寄存器来获取端口电平

开漏输出:寄存器输入高,mos断开,输出呈高阻态,输入低,mos导通,输出低电平。若想输出高电平,则在单片机外部提供上拉电阻。开漏输出的优点:1.提供电平转换(单片机3.3V供电,但上拉电阻连接的电源5V供电,因此可以给负载5V)2.提供线与功能(如I2C协议)



输入有两个去向(复用功能如串口RX 或 普通IO口的输入状态寄存器)当外部信号电压>=0.7Vdd为高,反之为低

浮空输入:比如IO口用于串口的RX时使用浮空输入模式,端口电平就完全取决于外部器件引脚电平。若用于按键检测,则需要在外部添加上拉/下拉电阻(取决于按键接地/VCC)

时钟树



数据跟踪监视单元DWT
和systick一样位于内核,DWT里有一个32位的寄存器叫CYCCNT,它是一个向上计数器,记录的是内核时钟运行的次数,内核时钟跳动一次,该计数器就加1,如果内核时钟是120MHz,那精度就是1/120M=8.3ns,而单片机程序的运行时间通常都是微秒级别的,所以DWT实现延时的精度是非常高的。
要实现DWT延时的功能,总共涉及到三个内核寄存器:DEMCR、DWT_CTRL、DWT_CYCCNT,分别用于开启DWT功能、开启CYCCNT及获得系统时钟计数值;当CYCCNT溢出之后,会清O重新开始向上计数。
如果内核时钟是120MHz,直接使用CYCCNT延时最大值为:232*1/120M=36S

中断

中断是异常的子集,异常包括系统异常和中断,系统异常指的是由内核产生的(复位异常,总线访问异常,systick异常等等)
触发源向量地址使用了地址重映射,向量地址中存储了对应中断服务函数的地址

EXTI5-9公用一个中断服务函数,同理EXTI10-15
中断优先级
优先级数值越小等级越高,是否抢占完全只由抢占优先级决定
systick
系统滴答计时器,计数方式为递减计数

volatile

对于while(!flag);这样的语句,编译器认为flag不会改变,便优化成只读取cpu寄存器的初始值,而不读后续的改变的值,加入volitale可以告诉编译器这个值是易变的,要多次读取寄存器值
使用场景:1.RTOS多线程中都会使用的变量2.中断和主程序都会使用的变量3.硬件寄存器数据可能被外部器件改变

串口

常用串口:UART SPI  CAN总线 USB

右上角是数据寄存器,读和写共用一个数据寄存器,它是32位的,但是实际可用的就是九位。当我们写程序的时候,数据寄存器写入数据会搬移到发送移位寄存器。左下角是波特率。当配置波特率为115200或者是9600的时候,移位寄存器就根据波特率的时钟,将这些数据一位一位的搬移到tx发送引脚上产生高低电平。对于接收功能rx引脚,当接收到了高低电平的时候,通过接收控制器,基于波特率的时钟采集rx引脚上的电瓶,然后获取到数据放在接收移位寄存器里面。再由它搬移到数据寄存器。当数据寄存器为空是TBE为1,当发送移位寄存器为空是TC为1

对于单片机系统,波特率=比特率=一秒钟传输多少数据位,常用9600和115200
奇偶校验位很少用,更常用的是针对一包数据进行校验,包括和校验异或校验,和校验是将所有的这些有效的数据进行求和。然后产生一个或者是两个字节放在末尾,接收方在接收到所有的数据的时候。再将前面的这些有效数据求和,将结果和最后的这一到两个校验数据进行比较。没有差错,就认为传输是正常的,异或校验是每一个字节都进行异或。最后把抑或的结果一个字节作为校验数据。
串口在发送和接收数据的时候,每一次一帧的数据就是八位有效数据。而不是16位或者是32位的。如果我们要想发送一个32位的数据,那需要拆分成一个字节一个字节进行发送。
还有一个最常用的校验方式叫做crc。循环融余校验,这个是用的最多的,它涉及到了一些数学运算。可以校验整个数据的完整性。像RS485使用Modbus协议的时候,要求最后两个字节。就是crc校验的数值。这是强制项。
串口使用场景:第一种mcu只发不收。printf第二种mcu只收不发,一些传感器啊。它就是周期性的主动的发送传感器的数据,不需要单片机发送。第三种mcu先发送命令再接收响应。典型的场景。比如开发板上有乐心的WIFI模组就是使用串口at命令来驱动的。单片机首先发送at命令给模组。然后模组再返回数据给单片机。第四种mcu首先接收到命令,然后再发送响应数据。典型的场景485modbus。此时mcu是从机。外部设备是主机。

队列

串口接收数据包时,若接收的速度大于读取的速度,第二包的数据会覆盖第一包的数据,因此使用环形队列

空闲中断

对于非空中断,每接收一个字节进入一次中断,在接收一个数据包时会多次进入终端,影响CPU主程序运行,因此改为:两个数据包之间的空闲时间窗(大概一字符帧即八位数据位,所消耗时间115200为1us,9600为1ms)会触发空闲中断
DMA
需要用到DMA(直接存储器访问)将数据包从数据寄存器依次搬运到内存中,减少CPU资源消耗

DMA的某个通道若要同时使能了I2C和串口使用,则当需要同时搬移数据的时候,就要看谁的优先级更高,就会去搬移谁的数据。

裸机任务调度



方案一大锅饭:浪费CPU执行资源
方案二时间片轮询:在while中不断使用if判断,程序可读性差
方案三时间片调度框架:利用系统滴答定时器中断处理函数对所有任务时间片计数,计满置标志位,主函数中不断扫描各个任务标志位,若真则通过函数指针变量间接调用

定时器



PWM
输出比较

输入捕获

不管有没有始能中断,只要产生了上升沿或者是下降沿,cnt寄存器里面的数值就会通过硬件自动的保存在CHxCV寄存器里面。
输入捕获时,CAR计数器可能出现溢出,解决方法有两种,1,调整预分频器从而增加计数间隔。2,在中断服务函数中判断cnt是否溢出,再进行数值运算

RTC实时时钟



通常选用32.768khz的低速外部时钟,可以在主电源掉电后有VBAT供电继续工作

时间戳与日历转换


在time模块中,自动进行了闰年闰月的计算

指针函数注意事项

使用指针函数时,返回的地址只有以下三种可能:要么是一个静态变量的地址,要么是一个全局变量的地址,或者是使用malloc等函数在堆上分配的空间;
不可返回非静态局部变量的地址,非静态局部变量是在栈上分配内存的,其生命周期仅限于函数的执行期间。当函数执行结束时,栈帧会被销毁,非静态局部变量所占用的内存空间会被自动释放。
如果返回malloc等函数在堆上分配的空间,在多次调用的时候记得使用free释放,长期不释放会造成内存泄露。

BKP备份寄存器


42个数据寄存器是易失性的,需要主电源或VBAT持续供电
RTC时钟通过PC16复用管脚输出信号,如果时钟偏差比较大,可以配置校准寄存器用来校准。使用侵入检测寄存器(也是PC 16复用)对这个管脚加上一个上拉电阻再通过导线连接开关,这个开关再连接到外壳上,外壳是接地的,当别人去拆这个壳子的时候。会触发开关闭合那PC 16这个管脚就变成了低电平,出现了高低电平的变化,产生侵入检测的事件,触发去清除BKP寄存器数据

看门狗


重装载寄存器=超时时间 / 1/(时钟频率*分频系数)             这里尾部不需要像定时器那样减1,因为看门狗递减到0会立刻系统复位

ADC模数转换


扫描模式针对的是某一个ADC使用多个通道。同步模式包括快速交叉模式,慢速交叉模式,交替触发模式,针对的是多个ADC一起或相互配合使用的场景(几乎都没有用过)
VDDA和VSSA是供电的电源。支持2.6V到3.6V,还有VREFP和VREFN参考电源。通常将VREFP也就是正电压连接到VDDA。所以对于模拟输入通道信号源的输入电压范围就是0到3.3V。
规则组只有一个数据寄存器,若不能及时取走数据,会出现旧数据被覆盖的问题,因此需要用到DMA自动的帮助我们将寄存器里面的数据拷贝到数组里面(在内存当中可以在程序当中定义五个元素的数组)

ADC转换完成以后,会产生eoc(end of convert)转换完成的标志,基于这个标志可以进一步的产生n vic中断。

触发源可以是定时器/EXTI外部中断/软件触发。注入组的转换优先去执行,执行完以后再去执行转换规则组。通常就使用规则组啊,就能够满足绝大部分的需求场景。单次模式每次ADC转换都需外部触发源触发。连续转换模式只需一次,后面自动完成触发一般使用右对齐

分辨输入电压变化最小值=参考电压/(2^分辨率位数)
触发转换后开关闭合,电容充电,充满后开关断开(采样保持),根据电容两端电压进行量化编码转换成数字量,若信号源输出阻抗超过了Rain max则电容没充满就抬起开关,造成采集精度下降。如果对采样转换的时间不敏感,可以将参数采样周期设置为最大值239.5,可以保证采样精度
信号源阻抗溢出解决办法:1.采用运放跟随电路减少信号源的输出阻抗  2.降低ADC采样频率提高采样时间 3.在功耗增大的代价下,减少信号源的输出阻抗


M=2^右移位数

快速排序和二分查找法


C标准库提供快排的接口函数,四个参数分别为(数组首地址,数组元素个数,数组元素对应内存空间大小,回调函数地址) 例子中为升序快排。若降序调换-1和1。基于快速排序可以实现基于它来实现中位值平均滤波。

使用mid=left+(right-left)/2而不是mid=(left+right)/2是为了防止求和时数据溢出

RS485电气协议


采用差分模式可以提高抗共模干扰能力,够得到更大的通信距离
方案一最常用,需要三个单片机IO口,
RE/DE用于控制收还是发,右侧为防护电路,抗干扰两个自恢复保险丝。可以起到过流保护的作用,防止电流过大烧毁器件。三个TVS管可以防止浪涌的干扰。在AB信号线之间可以加125Ω终端电阻(总线距离长的情况下)
方案二只需两个单片机IO口,为自收发电路,由于使用到了三极管,因此对应串口的波特率不能太高(可以9600)

Modbus通信协议


ASCII RTU这是跑在RS485和RS232这种电气接口上面的。而跑在以太网这种电器结果上面对应的报文类型是TCP。对于ASCII RTU,最常用的就是rtu模式。
在手撕modbus协议时一定要使用CRC校验,通常485总线很长,又有很多的干扰。非常有可能数据在传输的时候发生跳变,导致一包(帧)数据变成多包(帧)数据,造成数组越界。

相邻帧间隔要大于3.5个字符时间,一个帧的相邻字节要小于1.5个字符时间 (字符时间=10*字节时间)
使用串口中断接收modbus报文时,由于最后一位为不固定的CRC校验位,从机无法判断一帧的结束,因此只要超过3.5个字符时间就判断结束并触发中断(或者根据报文中的数据字节数判断最后一位),同时相邻字节间的间隔也采用3.5字符时间,可以节省CPU资源。较高波特率下,将导致频繁进入中断,因此协议规定当波特率大于19200bps时,帧开始或帧结束的时间间隔使用固定值1750μs,1750大于3.5个字符时间,采用此固定值满足协议的开始或结束标志;当波特率小于等于19200bps时则需要根据上述算式计算出3.5个字符的具体时间。

对于功能码最常用的有06,03,16。对于不同功能码,数据内容的长度就不一样,因此Modbus的数据包是不定长的
此处的寄存器不是单面机里面比如说定时器或者串口里面的硬件寄存器。而是一个虚拟的不是物理上的。可以理解为它是软件当中的一个控制项。比如写程序的时候去控制传感器,或者是继电器获取数据。25.5度,可以将它乘以十变成255。然后分成两个字节去传送。湿度也一样可以乘以十去传输

应答字节数0C= 数据内容总字节数12个字节


开源的freemodbus实现的是从机的功能 


单播:对单个从机进行读写,广播:主站的请求协议帧地址为零,进行写操作  
大小端:单片机默认小端,即低字节存低地址,高字节存高地址,在应用层读写回调函数中,调换数据指针顺序可以解决小端下数据颠倒问题
CRC校验:查表法(空间换时间)计算法(时间换空间)
计算法:(1)预置一个OxFFFF的16位数值,该数值作为CRC寄存器值。
(2)把消息帧中的第一个字节数据(即地址码)与寄存器值相异或,并把CRC寄存器
值更新为计算后的值。
(3)把CRC寄存器值往右移一位,用0填补最高位。
(4)如果被移出的位是0,则重复步骤(3);如果被移出的位是1,则当前CRC寄存
器值与OxA001进行异或,并把CRC寄存器值更新为计算后的值。
(5)重复步骤(3)和步骤(4),直到右移8次,这样一个字节的数据就处理完毕。
(6)重复步骤(2)至步骤(5),对消息帧的下一个字节进行处理。
(7)直至处理完消息帧中除校验码以外的所有字节,得到的就是一个计算完毕的十六
位值,将该值的高低字节进行调换,最终得到的就是正确的CRC-16值。即发送时先发送CRC
寄存器值的低字节,再发送CRC寄存器值的高字节。
注意:在串行链路中,只有8位数据位参与CRC计算,起始位、停止位和奇偶校验位
都不参与计算。
“Error: L6218E: Undefined symbol __aeabi_assert (referred from mbutils.o).”这种错误是因为启用了microlib库,它不支持assert()等与操作系统交互的函数,通过宏定义"NDEBUG"来禁用assert()

启动模式配置


从主闪存存储器启动:主闪存存储器被映射到启动空间(0x00000000),但仍然能够在它原
有的地址(0x08000000)访问它,即闪存存储器的内容可以在两个地址区域访问,0x0000
0000或0x0800 0000。默认的启动模式,主闪存具有非易失性
从系统存储器启动:系统存储器被映射到启动空间(0x00000000),但仍然能够在它原有的
地址(互联型产品原有地址为Ox1FFFB000,其它产品原有地址为Ox1FFFF000)访问它。
该模式存储了芯片制造商固化的引导程序和底层驱动程序
从内置SRAM启动:只能在0x20000000开始的地址区访问SRAM。SRAM 模式启动能够提供最快的启动速度,使系统在极短的时间内进入工作状态,SRAM 模式启动允许开发人员快速地将编译好的程序加载到 SRAM 中进行调试,无需像主闪存那样进行擦除和写入操作

作者:我不是兔子b

物联沃分享整理
物联沃-IOTWORD物联网 » ARM单片机自学指南与笔记分享

发表回复