编辑
2024-02-18
学习记录
0

1.新建用户

新建名字为name的用户

sudo useradd name -m -s /bin/bash -d /home***/name

重置用户密码

sudo passwd name

给名字为name的用户添加sudo权限
sudo vim /etc/sudoers name ALL=(ALL:ALL) ALL
删除名字为name的用户

sudo userdel -r name

2.修改密码

passwd ZZW

3.Windows和linux文件互传命令

scp C:\Users\sss\Desktop\MyWords.war root@114.116.225.111:/usrwebapps #当目标文件夹Permission denied时 sudo chmod 777 /home/users3

4.查看端口是否开放以及开放端口

查看

firewall-cmd --query-port=6379/tcp

开放端口

firewall-cmd --add-port=8888/tcp --permanent

移除端口

firewall-cmd --permanent --remove-port=123/tcp

5.安装x-ui适用于debian系统

apt update -y apt install -y curl socat bash <(curl -Ls https://raw.githubusercontent.com/vaxilu/xui/master/install.sh)

6.磁盘挂载

#在服务器中接上电源线和数据线后 df -h #未看到新磁盘,需要挂载 lsblk #看到新磁盘名字,格式化新磁盘,并新建磁盘需要挂载的目录 sudo mkfs -t ext4 /dev/sdb mkdir /home/users3 #挂载 sudo mount /dev/sdb /home/users3 #查看是否挂载成功 df -h #永久挂载 查看新磁盘的UUID,sda为新磁盘名 sudo blkid /dev/sda #修改配置文件信息 sudo vim /etc/fstab #添加 UUID=ef768810-a346-4285-8ba0-d1b8a619e97d /home/users3 ext4 defaults 0 0 #保存推出

7.vscode远程连接服务器不能跳转函数解决

安装python扩展,在python扩展设置中搜索jedi,将选项改为pylance

8.linux 下查看指定端口、所有端口、某个服务占用情况

#查看端口8080占用情况 netstat -tunlp |grep 8080 #查看服务器所有端口 netstat -ntlp #查看某进程端口占用,例Tomcat ps -ef |grep tomcat

9.vim与外部文件的粘帖复制

要实现外部文件与vim之间的粘帖和复制,ubuntu需要安装vim-gnome,用命令: sudo apt-get install vim-gnome安装。 "+y表示从vim复制到系统剪切版, "+p表示从外部文件(系统剪切版)粘帖到vim, "+d表示剪切. "+gp 粘贴并且移动光标到粘贴内容后

10.tar压缩解压缩

tar -czf file.tar.gz file/ //压缩 file/文件夹为gz格式,压缩包名称为 file.tar.gz tar -xzf file.tar.gz //解压缩 file.tar.gz压缩包 tar -cjf file.tar.bz file/ //压缩 file/文件夹为bz格式,压缩包名称为 file.tar.bz tar -xjf file.tar.gz //解压缩file.tar.gz压缩包. tar czf - file/ | split -d -b100m - file.tar.gz //将file文件夹进行分割,以100M大小进行分割操作,生产的压缩包格式为 file.tar.gz cat file.tar.gz0* | tar zx //将分卷压缩的压缩包进行统一解压缩操作。

11.ubuntu查看正在运行的python程序

ps -ef | grep python

12.查看linux系统信息

#查看系统内核信息: uname -a #查看系统版本信息: cat /proc/version #查看系统发行版本信息: cat /etc/issue #查看系统cpu相关信息,包括型号、主频、内核信息等: lscpu #查看系统名称: hostname #查看系统磁盘信息: lsblk

13.linux系统自动获得ip

#重新开机需要重新配置: sudo dhclient -r //release ip 释放IP sudo dhclient //获取IP #重启自动配置: vim /etc/network/interfaces #根本要设置的网卡添加以下示例内容: auto lo iface lo inet loopback auto eth0 iface eth0 inet dhcp #保存,执行以下命令使配置生效: sudo systemctl restart networking.service

14.git clone下载使用代理实例

git clone git clone https://mirror.ghproxy.com/https://github.com/stilleshan/dockerfiles

15.虚拟网络设置模式及注意点

三种模式: 1. 桥接:相当于开辟和主机相同网段的一个ip,虚拟机和外网互相通 2. net:在主机下形成一个局域网,虚拟机在这个局域网下,虚拟机可通外网,但外网通不了虚拟机。 3. 仅主机:在主机下形成一个局域网,虚拟机只能和主机以及在该局域网下的虚拟机互通。

在vmware里面给ubuntu16添加网卡后使用ip a查看有无对应网卡,有对应网卡,没有ip的话还需要设置对应的ip,ubuntu16是在/etc/network/interfaces中设置,如果要设置动态分配ip则可以按照以下图片添加。添加完成之后命令sudo service networking restart重启网络,即可对添加好的网卡分配ip。

image.png

注意一下几个选项:

image.png

一般是先主机的网络共享到虚拟机,然后在cmd中查看虚拟机的ip,然后再在虚拟网络编辑器中设置对应网段的ip,对于net是:

image.png

也要注意dhcp选项:

image.png

疑惑点

我在配置时当虚拟机配置为dhcp时,可以ping通baidu.com,但设置为静态地址时就ping不通baidu.com了,目前还没解决,猜测是DNS设置的问题!!!!

其他命令

#查看某个文件夹及子目录占用的内存空间 du -sh ./ (du -sh 路径) #查看当前文件夹及子目录所有文件数量 find . -type f | wc -l #查看当前文件夹中文件的数量(不包括文件夹) ls -l | grep "^-" | wc -l
编辑
2024-02-18
学习记录
0

卸载与安装步骤

1.卸载

win10 与 ubuntu 关于 EFI 的两种模式:

  1. win10 与 ubuntu 各自有单独的 EFI 分区
  2. win10 与 ubuntu 共用 EFI 分区

删除 win10 的 EFI 中的 ubuntu 文件夹(十分重要,否则开机你仍会进入grub引导,无法进入系统)

  1. EFI 分区 没有盘符我们没法访问,所以要为其分配盘符:
  2. WIN + R 键 输入 diskpart 进入磁盘管理(cmd版),然后输入 list disk 查看所有磁盘
  3. 我的 win10 的 EFI 在磁盘 0 ,所以输入 select disk 0 进入 磁盘 0,然后再输入 list partition 查看当前磁盘所有分区
  4. 100 M 的那个即为 EFI 系统分区,输入 select partition 1 选择分区,再输入 assign letter=p 为其分配一个 p 盘符(不区分大小写),注意不要关闭此窗口,后面有用
  5. 此时我们能看到但无法访问,因为没有对应权限,这里我们使用管理员身份打开记事本,用记事本访问盘 p,可以看到 EFI 文件,进入找到 ubuntu 删除即可
  6. 然后回到刚才的窗口,输入 remove letter=p 移除盘符 p
  7. 至此,此部分结束

删除 ubuntu 相关的分区

  1. 注意删除 ubuntu 的分区时不要动 win10 的 EFI 分区,无论是否共用 EFI 分区
  2. 以 swap 分区为例,在 win10 磁盘管理选中分区,右键选择删除卷

完成卸载,结束

2.安装

  1. 新建一块空闲磁盘空间(任意位置),如果电脑有两个磁盘,则在win的efi启动文件所在的磁盘新建200mb的空间用于存放ubuntu的efi启动。

  2. 准备好ubuntu的烧录盘。

  3. 开机进入BIOS,按照顺序安装。

  4. 更新和其他软件看个人喜好。

  5. 安装类型选择其他。

  6. 找到空闲磁盘进行手动分区。
    1)efi分区。如果是单硬盘,在唯一的一个空闲分区上添加,大小200M,主分区,空间起始位置,用于efi 。如果是双硬盘,在那个大小为200M的空闲分区上添加,大小200M,主分区,空间起始位置,用于efi 。

    2)swap分区。在空闲分区上添加,大小为你电脑的物理内存大小,逻辑分区,空间起始位置,用于"swap"或"交换空间"

    3)主分区。在空闲分区上添加,大小为剩下的所有空间,主分区,空间起始位置,用于"ext4日志文件系统",挂载点为"/"

7.选择安装引导启动器的设备找到刚才用于efi分区的设备号,安装引导启动器的设就选择这个设备号。 8.最后点击现在安装等待安装完成

apt更换为国内软件源

1.备份软件源配置文件sources.list

cp /etc/apt/sources.list /etc/apt/sources.list.bak

2.更换源

sudo gedit /etc/apt/sources.list
# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释 deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse # 预发布软件源,不建议启用 # deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse

3.执行更新

sudo apt-get update

安装vim,更改电脑默认启动顺序

sudo apt install vim
sudo gedit /etc/default/grub sudo update-grub

安装输入法 打汉字

1.在设置中的区域和语言中,安装Chinese(simplified)

2.ibus输入法安装

sudo apt-get install ibus ibus-clutter ibus-gtk ibus-gtk3 ibus-qt4 #ibus框架安装完成后,再切换到ibus框架 #切换到ibus框架之后,再接着安装中文拼音引擎 sudo apt-get install ibus-pinyin 然后调出 IBus Preference 窗口来添加该中文拼音输入法 sudo ibus-setup #在图形界面中add pinyin #在设置中的区域和语言中添加中文拼音输入法 #重启 完成!!!!!!!!!!!!

安装QQ VSCODE EDGE Anconda

1.下载qq官网deb文件:

sudo dpkg -i ***.deb

2.下载vscode官网deb文件:

sudo dpkg -i ***.deb #报错,需要依赖libvulkan1 sudo api install libvulkan1 #重新执行 sudo dpkg -i ***.deb

3.下载edge官网deb文件:

sudo dpkg -i ***.deb

4.下载anconda官网sh文件,注意不要安装在ubuntu根目录下面:

#官网下载sh文件 sudo bash Anaconda***.sh #安装过程选择yes,重新打开终端即可看到base环境 #更换pip源 conda源
编辑
2024-03-23
学习记录
0

imx6ull裸机开发

1.处理器区分:MCU、MPU、AP(Application Processor)

mcu = cpu + flash + RAM

2.GPIO操作方法

  1. 时钟使能寄存器;
  2. IO功能(复用)寄存器;
  3. 输入/输出寄存器;
  4. 值寄存器;

3.ARM架构

1.RISC精简指令集计算机和CISC复杂指令集计算机(核心:汇编代码);

2.汇编基本代码:内存访问、数据处理、跳转指令;

3.串口编程:

  1. 确定使用哪个串口并使能该串口的两个引脚;
  2. 设置串口参数:波特率、数据位、校验位、停止位;
  3. 根据状态寄存器读写数据;

4.gcc编译

1.过程:编译、汇编、反汇编、链接;

2.Makefile编写,简化汇编过程指令的操作;

5.段与代码重定位

在EMMC上烧写一个程序led.imx=头部+led.bin,头部中含有后面的led.bin读到那个addr(链接地址/运行地址),有多长len;上电后运行到ROM内的程序时,会根据头部信息将led.bin复制到内存中,并开始运行。

imx6ull和stm32f157中都有ROM中的程序将led.bin根据头部信息放在指示的位置。 stm32f103就没有这么强大的ROM,只能有程序本身把自己复制到指示的位置。

1.段的概念:将整个程序分成一个一个段,并起个名字,链接时用这个名字来指示这些段,使得这些段排布在合适的位置。内存中有程序段、可读可写数据段、只读数据段、BSS段(存放初始化为0和未初始化的变量,不需要重定位,使用的时候将那一块内存清零);(局部变量保存在栈里面)(堆是一块空闲的空间,app可以使用malloc管理);

2.重定位:

  1. 头部信息中的地址(加载地址)和链接地址不一致时需要重定位;
  2. 各个段的重定位。核心:内存的复制;
  3. 使用位置无关码来运行重定位之前的代码(要求只能使用相对跳转指令b、bl,不能用绝对跳转指令idr,不访问全局变量、静态变量、字符串、数组、重定位完后使用绝对跳转指令跳转到**函数的链接地址去);

3.散列文件和链接脚本

6.异常、中断与寄存器

1.处理过程:

  1. 保存现场(保存各个寄存器到栈中);
  2. 处理异常(中断);
  3. 回复现场(从栈中读取各个寄存器的值);

2.Cortex 7的cpu工作的模式9种:

  1. usr正常模式;
  2. sys系统模式;
  3. monitor模式
  4. Hyp模式
  5. 异常模式:
    1. und未定义指令模式;
    2. svc管理模式(一条指令svc #VAL,因为应用程序和内核程序是分开的,通过这种异常进入内核执行操作):
    3. abt中止模式;(指令预取中止、数据访问中止)
    4. IRQ中断模式;
    5. FIQ快中断模式(可快速处理); 3.und未定义指令异常和svc异常:核心都是异常的处理过程,根据开发手册保存恢复寄存器;

4.中断,三个部件:中断源、中断控制器、cpu

5.GIC中断控制器,作用:接收优先级最高的中断源分发给不同的CPU—interface,再发给相应的寄存器;

6.寄存器:

  1. ARM 体系结构提供了十六个 32 位通用寄存器(R0-R15)供软件使用。其中的 15 个(R0-R14)可用于通用数据存储,而 R15 是程序计数器,其值随处理器执行指令而改变。
  2. R13(在所有模式下)是堆栈指针,但是当堆栈操作不需要时,它可以用作通用寄存器。
  3. R14(链接寄存器)保存 BL 分支指令的下一条指令的地址。当它不支持子程序的返回时,它也可以用作通用寄存器。R14_svc,R14_irq,R14_fiq,R14_abt 和 R14_und 同样用于在发生中断和异常时,或者执行转移和链接指令时,备份 R15 的返回值。
  4. R15 是程序计数器并保存当前程序地址(实际上,在 ARM 状态下,它始终指向当前指令之后的八个字节,而在 Thumb 状态下,它始终指向当前指令之后的四个字节,这是原始 ARM1 的三级流水线的遗留特性)。在 ARM 状态下读取R15 时,位[1:0]为零,位[31:2]包含 PC 值。在 Thumb 状态下,位[0]始终读为零。
  5. 程序状态寄存器(CPSR,current programmer status register)包含处理器的状态和一些控制标记位。

image.png

6.GPIO中断:

  1. 使能分发器寄存器GICD_、设置目标cpu_interface;
  2. 使能寄存器GICC_、设置目标processor;
  3. processor读取相应寄存器确定中断;
  4. 清除中断;

7.IIC集成电路总线

1.写寄存器流程:

  1. master发起start;
  2. master发送slave的addr(7位) + w操作(1位)。等待ACK;
  3. slave发送ACK;
  4. master发送寄存器addr(8位),等待ACK;
  5. slave发送ACK;
  6. master发送date(8位),等待ACK;
  7. slave发送ACK;
  8. 第六步和第七步可以重复多次,顺序写多个寄存器;
  9. master发起stop;

11.读寄存器流程:

  1. master发起start;(下面先假写)
  2. master发送slave的addr(7bit) + w操作(1bit),等待ACK;
  3. slave发送ACK;
  4. master发送寄存器addr(8bit),等待ACK;
  5. slave发送ACK;
  6. master发起restart;
  7. master发送slave的addr(7bit) + r操作(1bit),等待ACK;
  8. slave发送ACK;
  9. slave发送data(8bit),即寄存器里的值;
  10. master发送ACK;
  11. 第9步和第10步可以重复多次,即顺序读寄存器里的值;
  12. master发送NO ACK表示读取完成,从机也不用发送ACK;
  13. master发送STOP;

8.SPI全双工同步串行通讯总线

1.四根线:SCLK\CS\MOSI\MISO;

2.MISO和MOSI在SCLK的上升沿变化,在下降沿锁存数据;

3.SPI控制器初始化流程:

  1. 清除 CONFREG 寄存器的 EN 位来复位模块;
  2. 使能 SPI 时钟,具体在 CCM 模块中进行设置;
  3. 配置控制寄存器,并使能 ECSPI_CONFREG 寄存器的 EN 位来让模块工作;
  4. 配置 SPI 引脚,具体在 IOMUX 中设置;
  5. 配置 SPI 引脚,具体在 IOMUX 中设置;

8.CAN总线

CAN总线是一种多主控(Multi-Master)的总线系统。CAN网络的消息是广播式的,即在同一时刻网络上所有节点侦测的数据是一致的,它是一种基于消息广播模式的串行通信总线。

CAN总线分高速CAN和低速CAN,收发器也分为高速CAN收发器(1Mbps)和低速CAN收发器(125Kbps)。低速CAN也叫FaultTolerance CAN,指的是即使总线上一根线失效,总线依然可以通信。如同串口中的MAX3232用作电平转换,CAN收发器的作用则是把逻辑信号转换为差分信号。

CAN总线采用差分信号传输,通常情况下只需要两根信号线就可以进行正常的通信。在差分信号中,逻辑0和逻辑1是用两根差分信号线的电压差来表示。当处于逻辑1,CAN_High和CAN_Low的电压差小于0.5V时,称为隐性电平(Recessive);当处于逻辑0,CAN_High和CAN_Low的电压差大于0.9V,称为显性电平(Dominant)。

CAN总线遵从“线与”机制:“显性”位可以覆 盖“隐性”位(和IIC相同);只有所有节点都发 送“隐性”位, 总线才处于“隐性” 状态。这种“线与”机制使CAN总线呈现显性优先的特性。

CAN网络通信是通过5中类型的帧(Frame)进行的:

  1. 数据帧(Data frame):节点发送的包含ID和数据的帧,用于发送单元向接收单元传送数据的帧。
  2. 遥控帧(Remote frame):节点向网络上的其他节点发出的某个ID的数据请求,发送节点收到遥控帧后就可以发送相应ID的数据帧:
  3. 错误帧(Error frame):节点检测出错误时,向其他节点发送的通知错误的帧
  4. 过载帧(Overload frame):接收单元未做好接收数据的准备时发送的帧,发送节点收到过载帧后可以暂缓发送数据帧。
  5. 帧间空间(Inter-frame space):用于将数据帧、遥控帧与前后的帧分隔开的帧。

9.各种模块

1.IRDA红外遥控模块(3个引脚):

  1. 一根线传输信号,单总线协议;
  2. 红外协议有NEC\SONY\RC5\RC6,常用的是NEC格式;
  3. NEC协议:引导码(9ms的低脉冲+4.5ms的高脉冲) + 数据(地址+地址取反+数据+数据取反)
  4. (注意:发送的数据1和0开始都是0.56ms的低脉冲,对于数据1后面的高脉冲比较长;如果遥控器长按则发送一个9ms的低脉冲+2.25ms的高脉冲的引导码;)

2.DHT11温湿度模块(3个引脚):

  1. 一根线传输信号,单总线协议;
  2. 通信发送过程:
    1. 主机与DHT11没有通信时,总线处于空闲状态,此时总线电平由于上拉电阻处于高电平;
    2. 主机将对应的GPIO管脚配置为输出,发送一个开始信号(一个低脉冲 + 一个高脉冲。低脉冲至少持续18ms,高脉冲持续20-40us);
    3. 主机将对应的GPIO管脚配置为输入,准备接收数据,此时信号由上拉电阻拉高;
    4. DHT11发出响应信号(一个低脉冲 + 一个高脉冲。低脉冲持续80us,高脉冲持续80us);
    5. DHT11发送数据(8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit湿度小数数据+8bit校验和,数据传输正确时,校验和等于前32位数据的末8位。信号0表示为一个50us的低脉冲+26~28us的高脉冲;信号1表示为一个50us的低脉冲+70us的高脉冲。)
    6. DHT11发送结束信号;

3.DS18B20温度模块(3个引脚):

  1. 通讯时序:

    1. 最开始引脚上拉为高电平;
    2. 主机必须要拉低至少 480us,复位,随后释放总线,等待15~60us;
    3. 如果GPIO 上连有 DS18B20 芯片,它会拉低 60~240us。
    4. 如果主机在最后检查到 60~240us 的低脉冲,则表示 DS18B20 初始化成功
    5. 写时序:
      1. 如果写 0,拉低至少 60us(写周期为 60-120us)即可;
      2. 如果写 1,先拉低至少 1us,然后拉高,整个写周期至少为 60us 即可。
    6. 读时序:
      1. 主机先拉低至少 1us,随后读取电平,如果为 0,即读到的数据是 0,如果为 1,即可读到的数据是 1。
      2. 整个过程必须在 15us 内完成,15us 后引脚都会被拉高。
  2. DS18B20 中有两类命令:ROM 命令、功能命令

  3. 总线上只一个 DS18B20 设备时,根据下表发送命令、读取数据。因为只有一个 DS18B20,所以不需要选择设备,发出“Skip ROM”命令。然后发户“Convert T”命令启动温度转换;

4.SR501人体红外模块(3个引脚):

  1. 人体恒温37度,会发出10uM左右特定波长的红外线;
  2. 通过跳线设置是否可以重复触发,默认为 L。其中 L 表示不可重复,H 表示可重复;
  3. 可以调节检测距离,修改封锁时间;
  4. 探测到人体时,红外模块会发生电平跳变,正常为低电平,有人活动跳变为高电平;

5.SR01超声波测距模块(4个引脚):

  1. 通信时序:
    1. 触发:向Trig脉冲触发引脚发出一个10us的高电平;
    2. 模块自动发送8个40Khz的超声波,遇到障碍物返回;
    3. 回响:模块发送完超声波后,Echo引脚输出高电平,接收到超声波后,Echo引脚输出低电平;
  2. 测量Echo的高电平时间(计数值除频率)×声波的速度340m/s,即可计算来回距离;

6.步进电机模块28BYJ-48:

  1. 其名称的含义为外径 28 毫米四相八拍式永磁减速型步进电机,B:表示是步进电机;Y:表示是永磁式;J:表示是减速型
  2. 4相B-A-D-C 的四节拍操作后,转子转过了1/8圈,每拍11.25度;在单四拍的每两个节拍之间再插入一个双绕组导通的中间节拍,组成八拍模式,每拍5.625度,
  3. 双路有刷直流马达驱动芯片 MX1508,有待机、正转、反转、刹车模式;

7.OLED显示模块:

  1. 驱动芯片 SSD1306可以驱动共阴型 OLED 面板。芯片内部包含晶振、显示 RAM、对比度控制模块以及 256 级亮度控制模块,大大降低了外围元器件数量和功耗。
  2. 为 0.96 寸的屏幕,支持 128×64 像素显示。
  3. 实际上,我们只需要把数据发给 OLED,不需要从 OLED 读取数据,所以 MISO引脚用不到。
  4. 另外,还需要一个 GPIO 来表示发送给 OLED 的是命令,还是数据。低电平是命令,高电平是数据。

8.DAC(Digital Analog Convector)模块:

  1. 性能指标:
    1. 分辨率: N 位 DAC 转换器,其分辨率为:1/(2^N-1)
    2. 精度线性度;
    3. 转换精度:影响转换精度的主要因素有失调误差、增益误差、非线性误差和微分非线性误差灯;
    4. 转换速度。
  2. 不同类型的DAC有不同的通讯方式,此处选用SPI接口的DAC芯片TLC5615,10位DAC;
  3. 最大输出两倍的参考电压,输出电压out = 2×V(参考)×占空比,范围是0到2×参考电压;
  4. 注意要输出16位,高四位和低二位置0,输出数字值0-1024给芯片前要左移两位;

9.EEPROM模块AT24C02:

  1. 用于掉电保存;
  2. AT24C02 是基于 I2C 总线的存储器件;
  3. 存储容量为2Kbit,即2048bit = 256×8bit = 256 Byte, 其中它被分为32页,每页8Byte。

10.GPS模块:

  1. 使用者接收机(即用户设备),追踪所有的 GPS 卫星,并实时的计算出接收机所在位置的坐标、移动速度及时间;
  2. GPS模块为集成模块,主板使用串口与其通信,波特率为 9600bps,1bit 停止位,无校验位;默认每秒输出一次标准格式数据。

11.ADC实验_光敏模块:

  1. 原理:有光照射电阻减小,无光照射高阻状态,在光敏电阻两端加一个电压,ADC检测电压就能得知光照变化;
  2. IMX6ULL 中有 2 个 ADC,每个 ADC 都有 16 个通道;
  3. ADC 精度最大为 12 位,最大采样率是 1M。它还有比较功能,当采样值小于、大于或是等于某个值时,可以设置让它发出中断;
  4. ADC 有 3 种状态:禁止(Disabled),空闲(IDLE)、正在转换(Performing conversions)。ADC 默认处于禁止状态,需要先配置它才能使用;
  5. 校准后使用,可以选择ADC_HC0 寄存器既可以用于软件触发,也可以用于硬件触发;
  6. 当 ADC 结束时,结果保存在 ADC_Rn 寄存器中,并且 ADC_HS[COCOn](硬件状态寄存器的转换结束标记)将被设置为 1,如果 ADC_HCn[AIEN]=1 的话还会触发中断。
  7. ADC 还有自动求平均值的功能,这叫硬件平均功能。通过 ADC_GC[AVGE]位来使能。
  8. ADC时钟源有4个可以通过 ADC_CFG[ADICLK]来选择;这个时钟还可以进一步分频,通过 ADC_CFG[ADIV]设置分频系数。
  9. 主要的寄存器:
    1. 控制寄存器ADCx_HC0,用来选择通道,用来控制软件触发 ADC;
    2. 状态寄存器 ADCx_HS,它的 BIT0 就是 COCO0,用来表示转换是否完成;
    3. 数据结果寄存器 ADCx_R0有效数据从 BIT0 开始存放,用不到的位值为 0;
    4. 配置寄存器 ADCx_CFG用来配置数据是否覆盖、计算平均值、参考电压、采样周期、时钟源、分频系数、采集速率、转换精度等;
    5. 通用控制寄存器 ADCx_GC来控制校准、转换模式和电压参考选择等;
  10. 代码编写配置过程:
    1. ADC初始化:选定精度、启动校准;
    2. 往 ADC_HC0 寄存器中写入值,选择 ADC 通道,即可启动 ADC 转换;
    3. 获取ADC值;
编辑
2024-03-27
学习记录
0

STM32F1 + RTOS + HAL

1.堆和栈

  1. 堆是一块空闲的内存空间,用,户自己管理使用malloc取出内存,用完后free释放;
  2. 栈也是一块内存空间,CPU的SP寄存器指向它,可以用于函数调用、局部变量、多任务系统里保存现场;

2.任务的三要素:

  1. 函数
  2. 优先级

3.创建任务:

使用xTaskCreate和xTaskCreateStatic创建任务;

4.创建不同的任务(传入参数)调用同一个函数;

5.任务的删除:用遥控器控制音乐;

6.增加任务优先级,将演示函数换成vTaskDelay即可改变音乐播放效果;

7.任务的状态:运行、就绪、阻塞、暂停

image.png

8.调度(每个tick后遍历ReadList,发起一次调度):

  1. 相同优先级的任务轮流运行;
  2. 最高优先级的任务先运行:
    1. 如果为执行完放弃运行状态的话,低优先级任务永远无法运行;
    2. 一旦高优先级任务就绪,马上执行;
    3. 如果最高优先级任务有多,会轮流执行;

9.任务必须处于死循环中

如果一个任务不是死循环的话,执行完后会进入preTaskExitError()函数,该函数关闭中断进入死循环,这时所有任务都无法执行。

10.任务如何退出:

  1. 自杀:vTaskDelete(NULL);空闲任务收尸;
  2. 他杀:vTaskDelete(handle);杀人犯收尸(释放TCB、栈);

11.为了避免空闲任务得不到机会执行,要有良好的编程习惯:

  1. 事件驱动(有了某个事件触发后才运行,其他事件处于阻塞状态);
  2. 延时函数不要使用死循环;

12.vTaskDelay和vTaskDelayUntil区别

vTaskDelay阻塞函数和vTaskDelayUntil阻塞函数,前者绝对延时,后者在一个任务里相对延时(任务+延时固定等于设置的时间);

13.同步与互斥方法:

  1. 使用全局变量同步(需要使用volatile修饰),死等效率低;
  2. 全局变量保护共享资源,大概率没问题,但理论上运行上千万次后可能出现问题,可以使用关中断开中断的方式保证全局变量的值修改过程中不被打断,但效率还是不够高因为A运行过程中虽然B不能运行不能造成bug,但tick中断时总会到B任务里去判断一下,B没事就来插一脚,效率不高;
  3. 两个任务如果不考虑阻塞唤醒和效率,就可以使用环形缓冲区来实现资源的同步访问,一个只操作写,一个只操作读,不会产生资源竞争。
  4. 队列中,数据读写的本质是环形缓冲区的基础上增加了互斥措施、阻塞-唤机制;

14.遥控器和编码器多个设备玩游戏;

15.队列集,存放每个队列的句柄,目的便于业务和硬件解耦;

16.MPU6050玩游戏

创建初始化、获取数据,写队列函数,然后将改队列加入队列集,统一处理三个队列;

17.三个任务读一个队列

如果三个任务都要读一个队列,可以在写队列是进行内容分发(写多个队列),写那些队列可以由应用程序调用驱动程序里的一个注册函数(自己创建一个数组存队列句柄);

18.信号量本质

也是一个队列,只不过不涉及数据的真正传输,只涉及队列里数据的个数;

19.信号量涉及的函数:

  1. 创建信号量
    或者xSemaphoreCreateCountion;
  2. 获得信号量
    (handle,超时时间);
  3. 释放信号量
    (handle);

20.优先级反转:

低优先级任务运行,高优先级任务不运行,可以是因为高优先级任务在等待信号量;

21.优先级反转问题解决

互斥量解决优先级反转的问题;也可以解决全局变量作为资源保护的方法存在的问题;

22.事件组

高八位不用,其余位每位表示一个事件,由程序决定; 还有一个链表,里面存放等待的事件(等待什么事件、等待事件的关系:或还是与);

23.事件组使用:

定义事件组; 写事件; 等待事件;

24.任务通知:

队列/信号量/事件组是都不知道是哪个任务提供的数据的,也不知道要唤醒什么任务; 任务通知是在中断或者某个任务中明确知道要通知哪个任务;

25.软件定时器:

  1. 定时器就是一个结构体,定义了一次性还是周期性、周期是多少、执行的函数、参数、链表
  2. 每个tick中断都会判断软件定时器链表的第一个有没有到时间,如果有则执行函数;

26.两套函数的区别

一个在中断中使用,一个在普通任务中使用,因为中断要求快速执行完,不会阻塞,只会记录是否有更高优先级的任务要执行而不切换,执行完中断处理函数后再进行切换;

27.资源管理

谁和我抢,我就毙掉谁;中断来了屏蔽中断,其他任务来了关闭任务调度;

28.优化系统:

精准的调整栈空间:栈由堆得来的,栈初始化时写入0xa5a5a5a5,函数调用过程中栈指针从上往下移动,会写入不同的数值,大概率与初始值不同,所以从栈最低端往上遍历值为0xa5a5a5a5的栈,栈的大小就是空闲的栈。

29.统计任务信息

可以在钩子函数中调用函数一次获得所有任务的栈空闲大小、优先级、任务序号等信息

30.统计CPU占比

通过统计任务的时间在每个tick中占比累加;

编辑
2024-03-26
学习记录
0

imx6ull应用开发基础

1.shell脚本

  1. .s格式的文件,第一行必须是#!/bin/bash;
  2. echo打印命令;
  3. read命令:读取命令行的输入;
  4. &&和||:命令1 && 命令2,表示命令1执行并且正确后命令2执行;命令1 || 命令2,表示命令1执行并且错误后命令2执行;
  5. test命令:查看文件是否存在、两个字符串是否相等、两个值比大小等;
  6. 中括号[]判断符,整体输出真或假;
  7. 默认变量:0表示命令行第一个参数./.sh0表示命令行第一个参数./**.sh;1-n表示第一个到底n个参数;n表示第一个到底n个参数;#表示参数的数量;$@表示所有的参数;
  8. 判断:{if [表达式]:then (执行语句) fi};或者{if [表达式]:then (执行语句) else (执行语句) fi};或者{if [表达式]:then (执行语句) elif [表达式]:then (执行语句) else (执行语句) fi};
  9. 判断:case:{case $val in "值a") (执行语句) ;; "值b") (执行语句) ;; '*') (执行语句) ;; esac}
  10. 函数
    函数名(){函数体};
  11. 循环:{while [表达式] do (执行语句) done};{for val in con1 con2 ... do (执行语句) done};{for((初始值; 限制值; 执行步长)) do (执行语句) done};

2.GCC

  1. 预处理:.c中的头文件找到、宏展开、编译开关展开,得到.i文件;
  2. 编译:得到汇编文件.s(语法错误在该过程中发现);
  3. 汇编:得到机器码文件.o;
  4. 链接:链接为一个应用程序;

3.Makefile文件及编写规则

4.文件IO

  1. 用到的函数:open、creat、write、read;
  2. 文件IO系统调用内部机制
    调用glibc写的系统接口访问Linux内核提供的服务(触发异常 )(文件句柄和文件install绑定的时候回产生一个task_struct结构体(每个进程都有一个),其里面有一个files成员,其里面有个fdt成员,其里面有个fd数组,对应进程的各个句柄对应的文件值);
  3. 两次读一个文件,各读各的,f_pos互相不影响,使用fd2=dup(fd1)是在fd数组中新建的句柄指针fd2指向被复制的数组fd1所以f_pos是一样的。(dup也可指定别的句柄(dup2(fd1,*)));

5.Framebuffer

  1. 控制LCD;
  2. freetype显示单个文字、显示旋转的文字、显示一行文字;

6.各种编码方式

ASCII编码、ANSI编码、字符集、unicode编码(UTF16-LE编码、UTF16-BE编码、UTF8编码)

7.读取输入设备信息

  1. 查询方式;
  2. 休眠唤醒方式;
  3. POLL/SELECT方式(定个闹钟,到时间了看一下);
  4. 异步通知方式(驱动程序主动告知app);

8.网络编程(类似文件传输有源\目的\长度)

  1. TCP(可靠、重传、有链接);
    1. 服务端
      1. fd=socket()
      2. bind(自己的ip,端口)
      3. listen(开始监测数据)
      4. accept(建立一条连接)
      5. send发送数据
      6. recv接收数据
    2. 客户端
      1. fd=socket()
      2. connect(目的)
      3. send发送数据
      4. recv接收数据
  2. UDP(不可靠、无连接);
    1. 服务端
      1. fd=socket()
      2. bind(自己的ip,端口)
      3. recvfrom/send_to
    2. 客户端
      1. fd=socket()
      2. connect(实际没有使用)
      3. send发送数据
      4. recv接收数据

9.多线程编程

进程的话是两个main函数,内部函数需要通信。线程的话是一个main函数,内部线程可以通过全景变量传递信息;

10.TTY体系中设备节点

  1. TTY/Terminal/Console/UART区别;
  2. TTY驱动程序框架(RXT TXT--UART--uart_driver--line_displine行规程);

11.串口应用程序编程

  1. ARM从高电平->低电平开始计时,保持1bit时间(开始位);
  2. ARM根据数据驱动TXD电平,bit[0]、bit[1]...bit7;
  3. (奇/偶校验位)数据位中为1的个数;
  4. (奇/偶校验位)数据位中为1的个数;
  5. ARM->高电平(停止位);

12.IIC应用编程

  1. 协议价绍(看裸机开发);
  2. SMBus协议(IIC的拓展);
  3. IIC系统重要的结构体:
    1. 控制器:I2C_Adapter(num第几个iic总线,xfer传输函数);
    2. 设备:I2C_Client(addr设备地址,adapter表示挂在哪个iic控制器上);
    3. 数据传输:I2C_msg(addr从设备地址,flag读还是写,buffer数据,len长度);

Linux内核中一般有了iic的驱动程序Adapter-DRV,提供了iic总线的读写能力,应用程序可以通过i2c-dev.c访问到Adapter-DRV进而控制iic总线;

13.IIC-Tools访问iic设备:

  1. 指定IIC控制器:i2c-dev.c为每个I2C控制器都生成了一个设备节点/dev/i2c-0、/dev/i2c-1,使用open某个设备节点/dev/i2c-x,就是访问该I2C控制器下的设备;
  2. 指定IIC设备:通过ioctl指定iic设备的地址,具体使用ioctl(file,I2C_SLAVE,addreess)或者ioctl(file,I2C_SLAVE_FORCE,addreess)。
  3. 传输数据:使用SMBus协议方式:ioctl(file,I2C_SMBUS,&args)或者iic协议
    (file,I2C_RDWR,&rdwr);

imx6ull驱动开发基础

1.怎么写一个驱动程序

  1. /* 1.确定主设备号 */
  2. /* 2.定义自己的file_operation结构体 */
  3. /* 3.实现对应的open/read/write等函数,填入file_operation结构体 */
  4. /* 4.把file_operation结构体告诉内核:注册驱动程序 */
  5. /* 5.谁来注册驱动程序,需要有一个入口函数,安装驱动程序时,就回去调用这个入口函数 */
  6. /* 6.有入口函数就有出口函数:卸载驱动程序时就去调用这个出口函数 */
  7. /* 7.有入口函数就有出口函数:卸载驱动程序时需要将注册的驱动程序去除 */

2.普适GPIO引脚操作方法

  1. 时钟使能;
  2. 模式选择;
  3. 输入/输出;
  4. 值;

注:读写寄存器的时候不要影响到其他位;(读、置位、写)

2.1 AM335x和AM437x的GPIO操作方法

  1. AM335X有gpio0-gpio3;AM437有gpio0-gpio5;gpio0常使能、其他的通过PRCM模块来控制使能状态;
  2. PRCM:Power,Reset,and Clock Managenment
  3. 拿到一个开发板配置GPIO要看他的芯片手册中GPIO章节、PRCM章节和Control Module章节;
  4. 配置某个引脚工作于GPIO模式:
    1. 在原理图上找到pin number;
    2. 根据pin number确定芯片手册中的pin name;
    3. 根据pin name在芯片手册的Control Module章节确定该引脚的寄存器(基地址+偏移地址);

2.2 RK3288和RK3399的GPIO操作方法

  1. RK3288有gpio0-gpio8;RK3399有gpio0-gpio4;每组GPIO分abcd四个小组gpio(0-7);
  2. 每组GPIO都有Data RegisterI(输出用)、Data Direction Register、EXT Data Register(输入用);
  3. 使能GPIO时钟寄存器:CRU(Clock & Reset Unit)时钟和复位单元;
  4. 设置GPIO模式寄存器:对于gpio1-8:PMU(Power Managerment)电源管理单元、对于gpio0:GRF(General Register Files)通用寄存器文件;

2.3 imx6ull的GPIO操作方法

  1. 有5组GPIO,每组最多有32个引脚;
  2. 使能某一组gpio时钟:CCM(Clock Controller Module);
  3. 设置gpio引脚模式:IOMUXC(包括MUX_MODE和SW_PAD_CTL两个寄存器,分别用来选择模式和是否上拉、回环等等);
  4. 设置gpio寄存器:输入还是输出GPIO_GDIR(还有中断寄存器等)、值多少GPIO_DR、状态GPIO_PSR;

2.4 STM32MP157的GPIO操作方法

  1. 内部有两个Cortex-A7核,一个Cortex-M4核;
  2. 要先使能PLL(PLL4)时钟本身,才能使能GPIO时钟;
  3. 使能GPIO时钟:RCC_MP寄存器或者RCC_MC寄存器;
  4. 设置GPIOX_MODER寄存器配置工作为GPIO模式、输入/输出;

3.最简单的LED驱动程序

  1. app只能open/read/write/ioctl;
  2. app——file_operation结构体——访问硬件;
  3. file_operation结构体是驱动程序的核心;
  4. app和驱动程序通过copy_to_user和copy_from_user传输数据;
  5. 驱动程序不可以直接访问寄存器的物理地址,需要通过ioremap把物理地址映射为虚拟地址进行访问;
  6. 编写led驱动程序,其实就是file_operation结构体中的读写、出入口函数等;
  7. 编写led测试程序(作为app);
  8. 编写Makefile后make编译得到.ko文件和生成的app,复制到开发板,使用insmod *.ko导入驱动程序(rmmod name 是卸载驱动程序);
  9. ls /dev/(驱动文件里写的名字) -l 查看有无对应的设备节点;
  10. 运行测试app;

4.LED驱动程序框架

额外知识:

  1. dmesg可以查看内核打印的信息;
  2. MMU(Memory Manager Unit)内存管理单元两大功能:
  3. 地址映射:CPU发出同样的地址(虚拟地址),执行不同的APP时,访问的是物理地址,由MMU执行中间的转换;
  4. 权限保护:CPU发出的地址,要经过MMU审核之后才可以访问具体硬件;

LED驱动程序框架:

  1. 找到原理图LED的引脚;
  2. 看芯片手册找到GPIO的时钟寄存器使能;
  3. 看芯片手册找到GPIO的IO_MUX寄存器复用为GPIO;
  4. 看芯片手册找到GPIO内部方向寄存器设置输入/输出;
  5. 看芯片手册找到GPIO内部数据寄存器 设置输出值/读输入值;
  6. 在每个开发板的驱动程序board.c中写对应开发板的led控制逻辑,修改寄存器值;抽象出来一个led_operation结构体;
  7. 使用中间层驱动leddrv.c(类似字符驱动框架)根据每个开发板的led_operation结构体进行LED控制;

5.驱动设计的思想

面向对象、分层、分离

  1. file_operation调get_board_led_opr调get_led_resouce;
  2. file_operation实现从app到led驱动的第一层驱动;
  3. get_board_led_opr实现所有关于led的io的初始化和控制关于led的io输出高低电平;
  4. get_led_resouce实现初始化芯片资源的哪个引脚(LED的话就选择led对应的引脚);

6.驱动设计的进化,总线设备驱动模型

image.png

  1. 分配/设置/注册platform_device结构体:定义所用资源,指定设备名字;
  2. 分配/设置/注册platform_driver结构体:在其中的probe函数里,分配/设置/注册file_operations结构体,并从platform_device中确定所用硬件资源,指定platform_driver的名字;

7.使用总线设备驱动模型改造LED模板驱动程序

  1. board_A.c:在入口函数中注册platform_device结构体,在 platform_device结构体中指定使用哪个GPIO引脚。
  2. chip_demo_gpio.c:注册platform_driver结构体使用Bus/Dev/Drv模型,当有匹配的platform_device时,它的 probe函数就会被调用,从匹配的platform_device中得到获取资源、确定引脚并创建设备。

8.驱动进化:设备树的引入

  1. 设备树文件dts、语法(格式、属性、常用的节点);
  2. 编译dts文件为dtb文件,在服务器make dtbs编译或者是手工编译,也可以反编译;
  3. 板子上/sys/firmware/fdt文件,就是 dtb 格式的设备树文件;

image.png

9.使用设备树改造LED模板驱动程序

  1. 修改服务器内核中的设备树文件添加led节点(包括宏、compatible属性、哪个引脚);
  2. 在chip_gpio.c在platform_driver结构体中添加of_match_table表示支持设备树,其中compatible的值需要和设备树文件对应;
  3. 在probe函数中,dev.of_node取出设备节点,并读出pin属性值;
  4. 创建设备节点的/dev/*,后面实现init和ctl;

10.按键驱动程序开发

相关概念:

  1. APP读取按键的方式:查询方式(循环查询)、休眠-唤醒方式(中断判断或rtos)、poll方式(闹钟+中断)、异步通知方式(按键自动通知);
  2. 驱动的基本技能:中断、休眠、唤醒、poll等机制;
  3. APP开发的基本技能:阻塞、非阻塞、休眠、poll、异步通知;

查询方式写按键驱动:

  1. button_drv.c实现file_operation结构体;
  2. board_xxx.c实现button_operations结构体;
  3. app调用button_drv调用board_xxx,不同单板修改board_xxx.c;

11.Pinctrl子系统

相关概念:

  1. 之前驱动思路:资源和驱动在同一个文件(一层驱动)->资源使用platform_devive指定,驱动在platform_driver实现->资源使用设备树指定,驱动在platform_driver实现;
  2. 每次操作都要查看寄存器引脚,很繁琐,利用Pinctrl子系统简化这部分操作(由bsp工程师完成),

12.GPIO子系统

相关概念:

  1. 实现在设备树里指定GPIO引脚;
  2. 在驱动代码中:使用 GPIO 子系统的标准函数获得 GPIO、设置 GPIO 方向、读取/设置 GPIO 值;
  3. 这样的驱动代码,将是单板无关的;

实现demo:

  1. 在命令行设置某个引脚(也提供了两个版本的代码供程序里使用):
  2. 在开发板目录:/sys/class/gpio下找到gpiochipxxx目录,进入后cat label查看该组gpio的基地址;
  3. 找到对应的gpiochipxxx,基地址xxx(可通过cat base查看)+io号就对应改组gpio的号码;
  4. 假设引脚号码为N,则在命令行可以配置方向和值等:
    1. echo N > /sys/class/gpio/export
    2. echo out > /sys/class/gpio/gpioN/direction
    3. echo 1 > /sys/class/gpio/gpioN/value
    4. echo N > /sys/class/gpio/unexport

12.Linux 系统对中断的处理

相关概念

  1. 对于耗时中断解决:1.分成上半部(硬件中断,无法处理其他中断)和下半部(软件中断,可以被中断打断,通过软件中断来实现);2.用内核线程(中断下半部作为一个线程,轮流执行);
  2. 硬件中断不能嵌套,软件中断可以;
  3. 软件中断是处理完硬件中断后顺便处理的;
  4. 为了避免中断下半部执行时间过长,内核有个worker线程,内部有个work queue会调度执行queue内的函数,所以当中断下半部需要执行的时间很长时,要先构造work结构体内部填充执行函数,在中断上半部执行完后把work放入work queue。
  5. 线程化中断:每个中断都创建一个内核线程,分配到多个cpu核上运行;
  6. 设备树里指定中断,irq_domain中有个xlate函数解析设备树中指定的irq_parent和interrapt,还有个map函数将硬件中断号映射为如软件中断号,会保存在palatform_device中,就可以使用request_irq注册这个中断处理函数了。
  7. 读取GPIO寄存器得到hwirq,根据hwirq得到之前映射的软件中断,既可以实现一个中断的硬件中断和软件中断的绑定。

13.编写使用中断的按键中断程序

对于GPIO按键,使用内核自带的驱动程序drivers/input/keyboard/gpio_key.c,只需要修改设备树指定的引脚及键值;

image.png

14.驱动程序的基石

1.休眠与唤醒

drv_read驱动程序中,读按键有值就返回,没有值就休眠,按键中断程序会唤醒app并把按键值传给app

2.POLL机制

中断+定时,检查有无数据没有数据则进入睡眠状态,如果还没有数据,休眠到时间后再去判断,超时退出; 内核帮忙实现了sys_poll,app调用sys_poll,内核函数调用驱动程序drv_poll(把线程放入work queue中,但不休眠,返回event状态,休眠在上层内核函数sys_poll中进行)。

3.异步通知

驱动程序发信号,app把自己的pid号给驱动程序; 使用kill_fasync(PID, SIGIO)发信号; app事先注册一个信号处理函数signal(SIGIO, func),收到信号后执行func函数;

image.png

4.阻塞与非阻塞

驱动程序能获得应用程序open文件传入的O_RDWR或O_NONBLOCK;

5.定时器(属于软件中断)

按键抖动会频繁发生中断,每次按键中断我们都忘后延迟20ms,这20ms是超时时间,按键稳定后超时再执行按键中断函数;

image.png

6.中断下半部tasklet

软件中断中有个tasklet_action队列,里面存放tasklet任务结构体,硬件中断执行完会将该中断的下半部的tasklet放入队列中,内核线程会去执行;

7.工作队列

在内核线程中执行; 驱动程序构造work(含有执行函数func),然后把work放入队列,最后唤醒;

8.中断的线程化处理

使用request_threaded_irq替换原来的中断注册函数request_irq image.png

9.mmap内存映射

基础知识:

  1. 用户态buffer和内核态buffer传数据要使用专门的函数,但当数据量大时就容易出现问题;
  2. 解决:mmap是把内核的buffer映射到用户态,让app在用户态直接读写内存;
  3. cache和buffer;
  4. cpu发出虚拟地址通过mmu内存管理单元找到对应的虚拟地址,具体的过程是通过页表映射实现;

代码编写:

应用程序编写函数格式可以在命令行执行“man 函数名”查看; image.png

imx6ull驱动大全