物联网感知层主控多为单片机。
51单片机内核是免费的。电容触摸IC(内带CPU)、Wifi芯片(ESP8266)、LoRa无线通信IC等专用Soc均有采用51内核。
开发板选择(普中科技):通过开发板学习,需要软硬结合。
制作开发板涉及采购,供应链等,个人制作是不可靠的。
需要的基础:编程基础和电学基础、英语、计算机基础知识、兴趣、时间。
CPU差异:是否有MMU,即虚拟地址映射。
操作系统差异:实时操作系统,linux操作系统。
应用领域差异:低端和中高端,低性能与中高性能。
单片机是低层次的嵌入式设备;嵌入式是单片机的高级延伸过和必然趋势。
物联网三层架构:
实现自下而上,自上而下双路径。
单片机是物联网感知层的核心。
单片机定义:属于计算机的一种。
组成如下:
中间部分为CPU模块,其他对应相应的外设模块。
内部外设:GPIO控制器、串口控制器、中断控制器等。
外部外设:至今没有集成到单片机内部的电路模块。
PCB板 = 基板(绝缘,玻璃纤维)+印刷电路
单层板、双面板、四层板、六层板等,覆铜之上一般会刷一层绝缘的油墨,避免氧化或与外部导电。
作用:构架和连接,硬件电路的载体。
硬件比较吃经验。电路板为产品,偏低端。20%
软件偏思维和逻辑。产品为代码,偏高端。80%
需要懂一些硬件,才能编程,以软件为主线,附带学习硬件。
工作职责:
工作职责:
初级:辅助测试、写代码、维护
中级:独立工作、对产品负责、调bug
高级:需求分析、框架设计、团队管理
学到基础(知识和能力)、找到工作、学习和锻炼、中级、高级/转方向
万用表
焊接套装
keil软件
51的单片机由Intel公司设计诞生,C8051内核,8位单片机。
热门:宏晶公司的STC51系列单片机。
发展趋势:
主频越来越高、内部外设越来越多、越复杂。
ROM和RAM越来越大。
集成其他模块做成专用SOC。包含通用性和专用型单片机。
https://www.stcmcudata.com/
1T单片机(高性能51单片机):12MHz分频为1MHz(6时钟周期、12时钟周期)
ISP/IAP支持,系统在线编程/在线编程。方便程序的烧录和升级,不在需要使用烧录器了,直接在开发板上通过USB口进行程序的烧录。
选用51单片机:STM89C52,8K ROM,512字节RAM
普中科技51单片机A2套件。
标准C语言独立于其他各种应用的编程语言,用途广泛。
keil C51是标准C语言的一种。
源码编写
编译生成可执行程序
烧录
仿真器用于替代单片机进行仿真,该设备价格非常贵。后来升级为调试器。
能工作的最小开销。
位(bit,b)与字节(byte,B):一个字节等于8位
单片机的IO物理上表现为单片机的引脚。
原理图分析
芯片数据手册阅读
分析:单片机P2输出高电平时,LED灭,输出低电平时,LED亮。
拷贝模板工程文件,修改组名:
右键管理组进入下图:
确认。
修改项目输出属性:
点亮LED的核心代码:
P2=0x00; //将P2端口全写0,即可点亮8个LED。
利用单片机小精灵软件生成此延时函数:
软件配置如下:
实际使用的是100ms的延时函数。
按键:用于用户与CPU交互。
处理方式:轮询(CPU每隔很短时间去查看一次按键是否被按下,效率低下)、中断(效率高)
按键接法:独立按键和矩阵键盘
原理图分析
分析:单片机P3口所接按键引脚读取到低电平时,表明此按键已经被按下,否则则没有被按下。
以检测P3.3所接按键是否被按下,如果被按下,则反转LED灯状态。
拷贝模板工程文件,修改组名:方法同流水灯实验。
SOC的一个内部外设。
定时器是CPU的“闹钟”。
定时器是使用计数来实现的。
可以计算外部脉冲个数。
设置时钟源头(内部脉冲源,用于计数的脉冲),定时时间等于脉冲时间*脉冲个数。
设定定时时间(计数个数)。
打开定时器。
设置中断处理函数。
定时器计数到后产生中断,CPU接收到此中断信号后,执行中断处理函数。
单片机学习内容:CPU和各种内部外设。
各种内部外设的编程接口就是寄存器。
熟悉一款单片机其实就是熟悉它的寄存器。
单片机越复杂则对应寄存器越多越复杂。
MSB:Most Significant Bit,二进制数中属于最高有效位。
LSB:Least Significant Bit,在二进制数中意为最低有效位。
相关寄存器:
具体每个寄存器及其相关位的详细介绍请看数据手册。
利用定时器定时实现LED灯闪烁:
代码编写:
拷贝模板工程文件,修改组名:方法同流水灯实验。
分析:定时0.5s,在定时器定时期间CPU还可以去做主任务,定时时间到产生中断,在中断处理函数中改变LED灯状态。
12T模式下,时钟频率为1MHz,时钟周期为1us。最多能定时65535(16位定时器),也就是最多能定位的时间为65535*1us=65535us=65.535ms。
如果需要定时500ms,则定时多次,然后进行累加。
计算TH0和TL0:(51单片机是加法计数器)
确定定时时间为:10ms
12T模式,外部晶振11.0592MHz,则实际周期为1/(11.0592MHz/12),即计数一次消耗的时间。
则计数个数为:10ms/(1/(11.0592MHz/12))=9216,计算过程中使用9215
TL0 =(65535-9615) % 256=0x00;低8位
TH0 =(65535-9615) / 256 =0xDC;高8位
单工:同一时刻,只能单方发送或者接收
半双工:同一时刻,一方能发送或者接收
全双工:同一时刻,一方既能发送又能接收
一、单工
数据只在一个方向上传输,不能实现双方通信。
栗子:电视、广播。
二、半双工
允许数据在两个方向上传输,但是同一时间数据只能在一个方向上传输,其实际上是切换的单工。
栗子:对讲机。
三、全双工
允许数据在两个方向上同时传输。
栗子:手机通话。
串行通信相关概念:
注意:对于串口的四种工作模式,只需要使用工作模式1即可。8位UART,波特率可变的模式。
其他三种工作模式不用理会。
查询方式处理串口发送数据: CPU并不知道串口什么时候将数据发送完,因此,CPU需要一直守着串口工作,效率低下。
中断方式:串口将数据发送完成后,硬件会自动将TI这个标志位置1,CPU收到此中断信号后,会去执行相关的中断处理函数。
注意:一般处理方式,发送数据使用轮询方式,接收使用中断方式。
拷贝模板工程文件,修改组名:
软件生成代码如下:
#include
void InitUART(void)
{
TMOD = 0x20;
SCON = 0x50;
TH1 = 0xF4;
TL1 = TH1;
PCON = 0x80;
EA = 1;
ES = 1;
TR1 = 1;
}
void SendOneByte(unsigned char c)
{
SBUF = c;
while(!TI);
TI = 0;
}
void main(void)
{
InitUART();
}
void UARTInterrupt(void) interrupt 4
{
if(RI)
{
RI = 0;
//add your code here!
}
else
TI = 0;
}
实际使用的程序:
实验效果:
JTAG
SWG
常用调试器:
JLINK
STLINK
stm32编程方式:
1.寄存器操作:容易出错,关注细节太多。
2.标准库:提供各种标准外设的驱动库。
2.hal库开发:集成各种第三方库。进行配置即可。
内存与IO统一编地址,像操作内存一样来操作这些寄存器。
上电复位,进行GPIO等状态的初始化。
数据总线32位,地址线32位。
逻辑地址(理论可以访问的地址),实际地址(实际可以访问的地址)。
内存与IO统一编址,操作内存一样的来操作IO。
内部外设的地址从0x4000 0000开始。
参考手册中就给了内部外设的内存映像。
别名存储区: 字(32位)
映射
位段存储区: 位
别名存储区和位段存储区为存储器中的2个地方。
有位段操作的原因?
51单片机支持位操作。stm32本身不支持位操作,只支持32位、8位和16位的操作,所以发明了此操作。将一位映射到其他的32位,操作32位就相当于操作这个位。
别名存储器区大小是位带存储器区大小的32倍。
三种启动模式:
ISP:在系统编程。可以在单片机运行过程中烧录程序。PC机通过串口将bin/hex文件直接isp到单片机flash中。
IAP:在应用编程。在线升级功能。自己更新自己。
CPU睡眠状态:CPU停,外设运行,唤醒源为所有中断。
CPU停止状态:CPU停,时钟停,外设停,只有SRAM和寄存器还保持原来的值,唤醒源为外部中断。
待机模式:CPU停,时钟停,外设停,SRAM和寄存器停,相当于断电,只有备份电路和备份寄存器工作,唤醒源为IWDG中断等。
系统启动刚开始是使用内部的时钟,一些初始化完成后,才开启外部时钟进行工作。
上电复位:执行复位中断函数。
时钟源:时钟产生源头,纯内部、内外部、纯外部
PLL:锁相环电路,功能就是倍频。
时钟通道与流向、分频
完全独立的多个时钟
完全独立的多个时钟。
系统上电后,默认时钟都是关闭的。使用内部的时钟。
ISP自动下载:不推荐使用。
分析:共2个LED可以进行控制,PF9控制LED0,PF10控制LED1。输出低电平,则LED亮。
编程思路:将PF9和PF10配置为输出,输出低电平就可以点亮LED。
创建工程模板Template:
选择开发板芯片:
关闭即可:
工程建立完成:
修改keil字体大小:
设置编码为utf8:
从CPU复位开始执行的第一条指令都main函数开始执行之前的代码。这段代码涉及CPU架构、CPU运行环境,编译器环境等。
不同CPU的起始代码是不同的。
GPIOF
地址:
模式寄存器: GPIOF_MODER 偏移量:0x00 实际地址:0x4002 1400
输出类型寄存器: GPIOF_OTYPER 偏移量:0x04 实际地址:0x4002 1404
输出速度寄存器: GPIOF_OSPEEDR 偏移量:0x08 实际地址:0x4002 1408
输出上下拉寄存器: GPIOF_PUPDR 偏移量:0x0C 实际地址:0x4002 140C
输出数据寄存器: GPIOF_ODR 偏移量:0x14 实际地址:0x4002 1414
位复位/置位寄存器: GPIOF_BSRR 偏移量:0x18 实际地址:0x4002 1418
ARM是内存与Io统一编址的。C语言通过操作这些地址来操作寄存器的。
配置GPIOF9和GPIOF10为输出模式:
即0X500。
输出上下拉寄存器
配置GPIOF9和GPIOF10为输出上拉:
即0X500。
输出数据寄存器
配置GPIOF9和GPIOF10为输出高电平:
即0X600。
调试器配置
注意:需要将此选项去掉,否则下载程序后,无法自动复位运行。
下载后,发现无现象。原因是时钟模块未开启。
由于时钟模块相对来说较复杂,从0开始容易出错,需要关注多个寄存器的细节。因此,对于这类问题,一般采用移植的方法。在别人的代码基础上进行修改。
这里选择忽略此时钟驱动的编写。
获取此开发板芯片的启动代码:
拷贝下图中文件到工程目录下:
添加到项目结构中:
添加头文件包含:
时钟相关寄存器
RCC:
地址:0x4002 3800
AHB1 peripheral clock enable register:即AHB1外设时钟使能寄存器
实际地址为:0x4002 3830
芯片产商提供数据手册和参考手册、实例代码、开发环境。
单片机软件工程师面向产品功能,查阅参考手册进行开发。
调试各种外设,而是实现产品功能。
外设库是芯片公司提供的示例代码的标准化产物。
创建SI工程
标准库文件结构:
CMSIS:ARM内核相关资料(CPU本身的东西)
STM32F4xx_StdPeriph_Driver:内部外设相关驱动
分析:学习过程中,一个一个模块进行代码分析。
使用结构体访问内存。结构体指针。
.c文件和.h文件都有宏定义。
.c文件中定义的宏定义只是给该C文件使用的,其他文件使用不了。而.h文件中定义的宏定义不仅对应的.c文件能使用,而且其他文件也能使用。
断言:用于判断传参是否可用。
配置界面如下:
配置LED引脚GPIOF9和GPIOF10:
配置为输出模式:
时钟配置:
默认使用的配置是使用内部提供的16MHz:
现在需要配置为使用外部晶振来生成最大工作频率:
生成后的时钟配置:
工程配置:
其他配置保持默认。
生成mdk代码
使用mdk打开项目:
生成的项目结构如下:
编译项目:
下载:注意只需要设置如下即可。
f4开发板原理图分析:
使用的是串口1
生成代码:
配置串口接收中断:
RS232通信距离不超过15m。
远距离传输要求:
提高电压标准;提供通信线抗干扰能力、降低阻抗;使用差分信号。
串口通信常用波特率为:9600和115200。
RS485最大通信距离1200M,最快通信速度为10Mps,距离和速度成反比。
差分信号负逻辑。
更远距离可以加中继。
半双工通信。
RS485只提供物理层通信能力,不提供数据层协议,需要用户自定义,或者使用标准协议,如MODBUS协议。
CPU本身只会提供UART接口,而不会提供RS485接口。
使用方法:UARTàRS485-àUART
RS485是纯硬件实现的,软件工程师只要关注串口就行,只通过串口将数据发送出去或者接收就可以了,UART转485和485转UART对CPU来说是透明的。
原理图分析:
连接的是UART2,其中的PG8用于控制数据的收发。
默认为接收模式。
功能需求:
默认485芯片是接收功能,每隔1s发送一个0x88,如果接收到0x55那么返回0x01,如果接收到的数据不是0x55就返回0x00。
运行结果:
可以基于串口(RS232、RS485和RS422)和以太网。主要分为3类。属于应用层接口。
Modbus ASCII
Modbus TCP/IP
Modbus RTU
关键在于编码和解码的过程。
看门狗定时器(iwdg)
分为独立看门狗和窗口看门狗。用于防止程序跑飞。
systick定时器:操作系统中使用,作为系统运行的滴答时钟。
可以用于产生RTOS的系统滴答时钟。
可以用于裸机程序中的短时间精确延时函数,HAL函数中的延时函数使用的就是这个。
可以用作普通定时器中断功能。
功能强弱分类:高级定时器(tim1-tim8)> 通用定时器(tim2-tim5、tim9-tim14)> 基本定时器(tim6-tim7)
实际开发过程中使用通用定时器就可以。
对于stm32f4定时器来说,具有14个定时器。比较复杂,学习思路如下:
首先学会基本功能的使用。就是定时,定一个时间,时间到就会执行中断服务函数。其他的高级功能可以等以后工作的时候使用到的时候再说。
选择通用功能定时器进行演示。
timer时钟频率为84MHz:
使能定时器4,预分频系数为4200-1,对应的分频频率为84MHz/4200=20KHz,自动重载值设置为35,得到超时时间1750us。
注意:定时1750us,则计数个数为:1750us/(1/20K)=35
若定时1s,,则计数个数为:1s/(1/20K)=20000
注意:实验过程中,发现这个位置设置成false和true都是可以的。
自动生成代码:
开启定时器中断:MX_TIM4_Init();
参考教程:https://blog.csdn.net/ASWaterbenben/article/details/105549750
为了简单处理,以串口1为例进行演示。
开启中断:
以定时器4为例,进行演示:
使能定时器4,预分频系数为4200-1,对应的分频频率为84MHz/4200=20KHz,自动重载值设置为35,得到超时时间1750us。
注意:定时1750us,则计数个数为:1750us/(1/20K)-1=35-1=34
打开定时器中断:
配置中断优先级:
配置中断优先级,定时器中断优先级低于串口中断即可
生成代码:
打开freeModbus代码包的demo文件夹,新建一个名为STM32MB的文件夹,之后将BARE文件夹内所有内容复制到STM32MB文件夹下,回到freeModbus代码包,复制整个modbus文件夹也粘贴到STM32MB文件夹内。
将STM32MB文件夹移动到stm32cubeMX生成的工程目录下,如图
打开工程,引入STM32MB内的所有头文件,并新建名为MB和MB_Port的组,MB内添加STM32MB文件夹下modbus文件夹内所有c文件以及根目录的demo.c文件,MB_Port内添加STM32MB文件夹下port文件夹内所有c文件,如图所示
编译报错:
修改demo中的main函数名称为host:
修改MB_Port下的portserial.c文件(串口设置)
其他移植过程省略:
测试:
软件配置:
移植成功:
NodeRed读取:
简介:实时操作系统
可以嵌套中断。
会什么要使用实时操作系统?
原因在于:为了实现多任务。
rtos学习什么?
应用开发,核心是任务创建、IPC、内存管理等。
应用开发(重点)à内核开发
功能实现:2颗LED以不同频率闪烁。
CMSIS:ARM Cortex微控制器软件接口标准。
use preemption:使用抢占。
max priorities
minimal stack size
idle should yield
use_mutexes
use recursive mutexes:使用递归缩
use counting semaphored:使用计数信号量
queue registry size:队列注册表大小
use application task tag:使用应用程序任务标签
enable backword compatibility:启用向后兼容性
use port optimized task selection:使用端口优化任务选择
use tickless idle: 使用无滴答空闲
内存管理:
use daemon task startup hook:使用守护进程任务启动钩子
check for stack overflow:检查堆栈溢出
generate run time stats:生成运行时统计信息
use trace facility:使用跟踪工具
max co routine priorities:最大协程优先级
interrupt nesting behavior configuration:中断嵌套行为配置
library lowest interrupt priority:库最低中断优先级
message buffer length type:消息缓冲区长度类型
use posix errno:使用 posix 错误号
heap still available
use newlib reentrant:使用 newlib 可重入
一共三个任务:
生成代码:
原来的tick设置:
修改后:
后面已经说明需要开启中断功能。
auto negotiation:自动协商
duplex mode:双工模式
Isolate phy from mll:从 mll 中分离 phy
valid link established:建立有效链接
其中Bits4:2就包含了PHY Speed mask和PHY Duplex mask的掩码,
Bits2代表两种速度10MB/s和100MB/s;PHY Speed mask(0x0004)
Bits4代表两种工作方式半双工和全双工;PHY Duplex mask(0x0010)
开启ETH中断:
注意:对于正点原子的板子,需要重映射:
注意PD3引脚的设置:
默认配置如下:
此处需要修改配置:
freeRTOS配置
LWIP配置
生成代码:
实验过程中发现,静态分配的Ip地址,过一会就失效了。
修改操作:
将freertos的标准重新进行修改:其他配置不用修改。
嵌套向量中断控制器
起始代码:帮我们建立起来了中断向量表。
外部中断实际编程过程:
1)设置时钟,打开相应GPIO模块时钟。
2)NVIC设置
3)将外部中断线使能触发
4)准备好ISR,在ISR处等待执行中断程序即可。
注意:NVIC和jtag调试并不是属于内部外设,而是属于CPU内部的东西,所以标准库中并不存在对应模块的库文件。
优先级:包含抢占优先级和次优先级,数字越小则优先级越高。
原理图分析:
取KEY0,PE4做实验。
设置下降沿触发:
配置NVIC设置中断优先级:
STM32的CPU判断优先级的方法如下:
1)先判断抢占优先级,数字越小,优先级越高;
2)若抢占优先级相同,判断子优先级,同样,数字越小,优先级越高;
配置使用中断优先级分组规则NVIC_PriorityGroup_2:
根据中断优先级分组规则NVIC_PriorityGroup_2来设置具体的优先级大小:
先打开stm32l4xx_it.c文件:
打开stm32l4xx_hal_gpio.c文件,看一下该函数的原型:
HAL_GPIO_EXTI_Callback(GPIO_Pin);
该函数称为EXIT中断的回调函数,用来处理所有发生的EXIT中断事件。
同样在stm32l4xx_hal_gpio.c文件中找到该函数的原型:
自己实现EXIT中断处理回调函数
放在gpio.c的最后:
编译下载工程:
注意需要给配置为中断检测引脚的初始状态为高电平。否则,实验无效果。