🌍首页
📁归档
⏳时光机
🚩友链
📫留言
📧订阅
🌟推荐
📕考研课程
🏜️ 免费壁纸
❤ 捐助本站
💰资助名单
🎵音乐实验
Search
1
【NPN/PNP三极管】放大电路饱和失真和截止失真的区别
20,260 阅读
2
论文写作中如何把word/wps里面所有数字和字母替换为新罗马字体
10,787 阅读
3
【高数】形心计算公式讲解大全
9,134 阅读
4
Vivado-FPGA Verilog烧写固化教程
8,201 阅读
5
【概论】一阶矩、二阶矩原点矩,中心矩区别与概念
7,919 阅读
🪶微语&随笔
励志美文
我的随笔
工作办公
📡电子&通信
嵌入式&系统
通信&信息处理
编程&脚本笔记
⌨️IC&系统
FPGA&ASIC
VLSI&IC验证
EDA&虚拟机
💻电子&计算机
IP&SOC设计
机器学习
软硬件算法
登录
/
注册
56(共77篇)
找到
77
篇与
56
相关的结果
- 第 5 页
【1】Verilog练习-基本门电路反相器&与非门
摘要本文介绍了Verilog语言中基本门电路的设计,包括反相器和与非门,并提供了相应的代码示例和测试用例。通过这些示例,读者可以了解如何使用Verilog实现基本的逻辑门电路。关键词:Verilog, 反相器, 与非门, 代码示例, 电路设计目录 反相器 多位反相器 与非门 多位与非门 反相器 图片 //反相器设计 `timescale 1ns/10ps //1ns时间单位,10ps精度 module inv( A, Y ); input A; output Y; assign Y=~A; endmodule //---testbench of inv-- module inv_tb; //testbench无端口不写括号 reg aa; //输入 wire yy; //输出 inv inv( .A(aa), .Y(yy) ); //异名例化 initial begin aa<=0; #10 aa<=1; //过10个时间单位timescale #10 aa<=0; #10 aa<=1; #10 $stop; end endmodule现象: 图片 多位反相器 图片 与非门 l378lznf.png图片 代码 //与非门 `timescale 1ns/10ps module nand_gate( A, B, Y ); input A; input B; output Y; assign Y=~(A&B); endmodule //------testbench of nand_gate-- module nand_gate_tb; reg aa,bb; //输入定义为reg wire yy; nand_gate nand_gate( .A(aa), .B(bb), .Y(yy) ); initial begin aa<=0;bb<=0; //用箭头等号对应实际电路 #10 aa<=1;bb<=1; #10 aa<=0;bb<=1; #10 aa<=1;bb<=0; #10 aa<=0;bb<=0; #10 $stop; end endmodule现象 l379jg44.png图片 多位与非门 l379koe9.png图片 代码 //与非门 `timescale 1ns/10ps module nand_gate_4bits( A, B, Y ); input[3:0] A; input[3:0] B; output[3:0] Y; assign Y=~(A&B); endmodule //------testbench of nand_gate-- module nand_gate_4bits_tb; reg[3:0] aa,bb; //输入定义为reg wire[3:0] yy; nand_gate_4bits nand_gate_4bits( .A(aa), .B(bb), .Y(yy) ); initial begin aa<=4'b0000;bb<=4'b1111; //用箭头等号对应实际电路 #10 aa<=4'b1110;bb<=4'b0011; #10 aa<=4'b0110;bb<=4'b0111; #10 aa<=4'b0111;bb<=4'b1110; #10 aa<=4'b1101;bb<=4'b1111; #10 $stop; end endmodulel379uc5u.png图片
FPGA&ASIC
刘航宇
4年前
0
723
2
2022-05-14
【3】Verilog-基础语法1
摘要本文介绍了Verilog的基础语法,包括标识符与关键字、数值种类、数据类型(如线网、寄存器、向量、整数、实数、时间、数组、存储器、参数和字符串)等,为Verilog编程提供了基础。关键词:Verilog, 语法基础, 标识符, 关键字, 数据类型目录 标识符与关键字 数值种类字符串表示方法 Verilog 数据类型 标识符与关键字 标识符(identifier)可以是任意一组字母、数字、$ 符号和 _(下划线)符号的合,但标识符的第一个字符必须是字母或者下划线,不能以数字或者美元符开始。 另外,标识符是区分大小写的。 关键字是 Verilog 中预留的用于定义语言结构的特殊标识符。 Verilog 中关键字全部为小写。 reg [3:0] counter ; //reg 为关键字, counter 为标识符 input clk; //input 为关键字,clk 为标识符 input CLK; //CLK 与 clk是 2 个不同的标识符数值种类 Verilog HDL 有下列四种基本的值来表示硬件电路中的电平逻辑: 0:逻辑 0 或 "假" 1:逻辑 1 或 "真" x 或 X:未知 z 或 Z:高阻 x 意味着信号数值的不确定,即在实际电路里,信号可能为 1,也可能为 0。 z 意味着信号处于高阻状态,常见于信号(input, reg)没有驱动时的逻辑结果。例如一个 pad 的 input 呈现高阻状态时,其逻辑值和上下拉的状态有关系。上拉则逻辑值为 1,下拉则为 0 。 整数数值表示方法 数字声明时,合法的基数格式有 4 中,包括:十进制('d 或 'D),十六进制('h 或 'H),二进制('b 或 'B),八进制('o 或 'O)。数值可指明位宽,也可不指明位宽。 指明位宽 4'b1011 // 4bit 数值 32'h3022_c0de // 32bit 的数值其中,下划线 _ 是为了增强代码的可读性。 不指明位宽 一般直接写数字时,默认为十进制表示,例如下面的 3 种写法是等效的: counter = 'd100 ; //一般会根据编译器自动分频位宽,常见的为32bit counter = 100 ; counter = 32'h64 ;负数表示 通常在表示位宽的数字前面加一个减号来表示负数。例如 -6'd15 -15-15 在 5 位二进制中的形式为 5'b10001, 在 6 位二进制中的形式为 6'b11_0001。 需要注意的是,减号放在基数和数字之间是非法的,例如下面的表示方法是错误的: 4'd-2 //非法说明实数表示方法 实数表示方法主要有两种方式: 十进制 30.123 6.0 3.0 0.001 科学计数法 1.2e4 //大小为12000 1_0001e4 //大小为100010000 1E-3 //大小为0.001 字符串表示方法 字符串是由双引号包起来的字符队列。字符串不能多行书写,即字符串中不能包含回车符。Verilog 将字符串当做一系列的单字节 ASCII 字符队列。例如,为存储字符串 "ee.ac.cn", 需要 14*8bit 的存储单元。例如: reg [0: 14*8-1] str ; initial begin str = "ee.ac.cn"; end Verilog 数据类型 Verilog 最常用的 2 种数据类型就是线网(wire)与寄存器(reg),其余类型可以理解为这两种数据类型的扩展或辅助。 线网(wire) wire 类型表示硬件单元之间的物理连线,由其连接的器件输出端连续驱动。如果没有驱动元件连接到 wire 型变量,缺省值一般为 "Z"。举例如下: wire interrupt ; wire flag1, flag2 ; wire gnd = 1'b0 ;线网型还有其他数据类型,包括 wand,wor,wri,triand,trior,trireg 等。这些数据类型用的频率不是很高,这里不做介绍。 寄存器(reg) 寄存器(reg)用来表示存储单元,它会保持数据原有的值,直到被改写。声明举例如下: reg clk_temp; reg flag1, flag2 ;例如在 always 块中,寄存器可能被综合成边沿触发器,在组合逻辑中可能被综合成 wire 型变量。寄存器不需要驱动源,也不一定需要时钟信号。在仿真时,寄存器的值可在任意时刻通过赋值操作进行改写。例如: reg rstn ; initial begin rstn = 1'b0 ; #100 ; //延时 rstn = 1'b1 ; end向量 当位宽大于 1 时,wire 或 reg 即可声明为向量的形式。例如: reg [3:0] counter ; //声明4bit位宽的寄存器counter wire [32-1:0] gpio_data; //声明32bit位宽的线型变量gpio_data wire [8:2] addr ; //声明7bit位宽的线型变量addr,位宽范围为8:2 reg [0:31] data ; //声明32bit位宽的寄存器变量data, 最高有效位为0对于上面的向量,我们可以指定某一位或若干相邻位,作为其他逻辑使用。例如: wire [9:0] data_low = data[0:9] ; addr_temp[3:2] = addr[8:7] + 1'b1 ;Verilog 支持可变的向量域选择,例如: reg [31:0] data1 ; reg [7:0] byte1 [3:0]; integer j ; always@* begin for (j=0; j<=3;j=j+1) begin byte1[j] = data1[(j+1)*8-1 : j*8]; //把data1[7:0]…data1[31:24]依次赋值给byte1[0][7:0]…byte[3][7:0] end endVerillog 还支持指定 bit 位后固定位宽的向量域选择访问。 [bit+: width] : 从起始 bit 位开始递增,位宽为 width。 [bit-: width] : 从起始 bit 位开始递减,位宽为 width。 //下面 2 种赋值是等效的 A = data1[31-: 8] ; A = data1[31:24] ; //下面 2 种赋值是等效的 B = data1[0+ : 8] ; B = data1[0:7] ;对信号重新进行组合成新的向量时,需要借助大括号。例如: wire [31:0] temp1, temp2 ; assign temp1 = {byte1[0][7:0], data1[31:8]}; //数据拼接 assign temp2 = {32{1'b0}}; //赋值32位的数值0 整数,实数,时间寄存器变量 整数,实数,时间等数据类型实际也属于寄存器类型。 整数(integer) 整数类型用关键字 integer 来声明。声明时不用指明位宽,位宽和编译器有关,一般为32 bit。reg 型变量为无符号数,而 integer 型变量为有符号数。例如: reg [31:0] data1 ; reg [3:0] byte1 [7:0]; //数组变量,后续介绍 integer j ; //整型变量,用来辅助生成数字电路 always@* begin for (j=0; j<=3;j=j+1) begin byte1[j] = data1[(j+1)*8-1 : j*8]; //把data1[7:0]…data1[31:24]依次赋值给byte1[0][7:0]…byte[3][7:0] end end此例中,integer 信号 j 作为辅助信号,将 data1 的数据依次赋值给数组 byte1。综合后实际电路里并没有 j 这个信号,j 只是辅助生成相应的硬件电路。 实数(real) 实数用关键字 real 来声明,可用十进制或科学计数法来表示。实数声明不能带有范围,默认值为 0。如果将一个实数赋值给一个整数,则只有实数的整数部分会赋值给整数。例如: real data1 ; integer temp ; initial begin data1 = 2e3 ; data1 = 3.75 ; end initial begin temp = data1 ; //temp 值的大小为3 end时间(time) Verilog 使用特殊的时间寄存器 time 型变量,对仿真时间进行保存。其宽度一般为 64 bit,通过调用系统函数 $time 获取当前仿真时间。例如: time current_time ; initial begin #100 ; current_time = $time ; //current_time 的大小为 100 end数组 在 Verilog 中允许声明 reg, wire, integer, time, real 及其向量类型的数组。 数组维数没有限制。线网数组也可以用于连接实例模块的端口。数组中的每个元素都可以作为一个标量或者向量,以同样的方式来使用,形如:<数组名>[<下标>]。对于多维数组来讲,用户需要说明其每一维的索引。例如: integer flag [7:0] ; //8个整数组成的数组 reg [3:0] counter [3:0] ; //由4个4bit计数器组成的数组 wire [7:0] addr_bus [3:0] ; //由4个8bit wire型变量组成的数组 wire data_bit[7:0][5:0] ; //声明1bit wire型变量的二维数组 reg [31:0] data_4d[11:0][3:0][3:0][255:0] ; //声明4维的32bit数据变量数组下面显示了对数组元素的赋值操作: flag [1] = 32'd0 ; //将flag数组中第二个元素赋值为32bit的0值 counter[3] = 4'hF ; //将数组counter中第4个元素的值赋值为4bit 十六进制数F,等效于counter[3][3:0] = 4'hF,即可省略宽度; assign addr_bus[0] = 8'b0 ; //将数组addr_bus中第一个元素的值赋值为0 assign data_bit[0][1] = 1'b1; //将数组data_bit的第1行第2列的元素赋值为1,这里不能省略第二个访问标号,即 assign data_bit[0] = 1'b1; 是非法的。 data_4d[0][0][0][0][15:0] = 15'd3 ; //将数组data_4d中标号为[0][0][0][0]的寄存器单元的15~0bit赋值为3虽然数组与向量的访问方式在一定程度上类似,但不要将向量和数组混淆。向量是一个单独的元件,位宽为 n;数组由多个元件组成,其中每个元件的位宽为 n 或 1。它们在结构的定义上就有所区别。 存储器 存储器变量就是一种寄存器数组,可用来描述 RAM 或 ROM 的行为。例如: reg membit[0:255] ; //256bit的1bit存储器 reg [7:0] mem[0:1023] ; //1Kbyte存储器,位宽8bit mem[511] = 8'b0 ; //令第512个8bit的存储单元值为0参数 参数用来表示常量,用关键字 parameter 声明,只能赋值一次。例如: parameter data_width = 10'd32 ; parameter i=1, j=2, k=3 ; parameter mem_size = data_width * 10 ;但是,通过实例化的方式,可以更改参数在模块中的值。此部分以后会介绍。 局部参数用 localparam 来声明,其作用和用法与 parameter 相同,区别在于它的值不能被改变。所以当参数只在本模块中调用时,可用 localparam 来说明。 字符串 字符串保存在 reg 类型的变量中,每个字符占用一个字节(8bit)。因此寄存器变量的宽度应该足够大,以保证不会溢出。 字符串不能多行书写,即字符串中不能包含回车符。如果寄存器变量的宽度大于字符串的大小,则使用 0 来填充左边的空余位;如果寄存器变量的宽度小于字符串大小,则会截去字符串左边多余的数据。例如,为存储字符串 "ee.ac.cn", 需要 14*8bit 的存储单元: reg [0: 14*8-1] str ; initial begin str = "ee.ac.cn"; end 有一些特殊字符在显示字符串中有特殊意义,例如换行符,制表符等。如果需要在字符串中显示这些特殊的字符,则需要在前面加前缀转义字符 \ 。例如下表所示: 图片 其实,在 SystemVerilog(主要用于 Verilog 仿真的编程语言)语言中,已经可以直接用关键字 string 来表示字符串变量类型,这为 Verilog 的仿真带来了极大的便利。有兴趣的学者可以简单学习下 SystemVerilog。
FPGA&ASIC
刘航宇
4年前
0
1,467
2
2022-05-14
【2】Verilog-项目设计方法
摘要Verilog设计采用自上而下方法,先定义顶层模块,再分解设计至底层功能块。设计流程包括需求分析、功能划分、文本描述、功能仿真、逻辑综合、布局布线、时序仿真,最后下载至FPGA/CPLD或制造ASIC芯片。关键词:Verilog, 设计方法, 顶层模块, 逻辑综合, 时序仿真目录 设计方法 设计流程需求分析 功能划分 文本描述 功能仿真(前仿真) 逻辑综合 布局布线 时序仿真(后仿真) FPGA/CPLD 下载或 ASIC 制造工艺生产 设计方法 Verilog 的设计多采用自上而下的设计方法(top-down)。即先定义顶层模块功能,进而分析要构成顶层模块的必要子模块;然后进一步对各个模块进行分解、设计,直到到达无法进一步分解的底层功能块。这样,可以把一个较大的系统,细化成多个小系统,从时间、工作量上分配给更多的人员去设计,从而提高了设计速度,缩短了开发周期。 l35lheq6.png图片 设计流程 l35ligw8.png图片 Verilog 的设计流程,一般包括以下几个步骤: 需求分析 工作人员需要对用户提出的功能要求进行分析理解,做出电路系统的整体规划,形成详细的技术指标,确定初步方案。例如,要设计一个电子屏,需要考虑供电方式、工作频率、产品体积、成本、功耗等,电路实现采用 ASIC 还是选用 FPGA/CPLD 器件等。 功能划分 正确地分析了用户的电路需求后,就可以进行逻辑功能的总体设计,设计整个电路的功能、接口和总体结构,考虑功能模块的划分和设计思路,各子模块的接口和时序(包括接口时序和内部信号的时序)等,向项目组成员合理分配子模块设计任务。 文本描述 可以用任意的文本编辑器,也可以用专用的 HDL 编辑环境,对所需求的数字电路进行设计建模,保存为 .v 文件。 功能仿真(前仿真) 对建模文件进行编译,对模型电路进行功能上的仿真验证,查找设计的错误并修正。 此时的仿真验证并没有考虑到信号的延迟等一些 timing 因素,只是验证逻辑上的正确性。 逻辑综合 综合(synthesize),就是在标准单元库和特定的设计约束的基础上,将设计的高层次描述(Verilog 建模)转换为门级网表的过程。逻辑综合的目的是产生物理电路门级结构,并在逻辑、时序上进行一定程度的优化,寻求逻辑、面积、功耗的平衡,增强电路的可测试性。 但不是所有的 Verilog 语句都是可以综合成逻辑单元的,例如时延语句。 布局布线 根据逻辑综合出的网表与约束文件,利用厂家提供的各种基本标准单元库,对门级电路进行布局布线。至此,已经将 Verilog 设计的数字电路,设计成由标准单元库组成的数字电路。 时序仿真(后仿真) 布局布线后,电路模型中已经包含了时延信息。利用在布局布线中获得的精确参数,用仿真软件验证电路的时序。单元器件的不同、布局布线方案都会给电路的时序造成影响,严重时会出现错误。出错后可能就需要重新修改 RTL(寄存器传输级描述,即 Verilog 初版描述),重复后面的步骤。这样的过程可能反复多次,直至错误完全排除。 FPGA/CPLD 下载或 ASIC 制造工艺生产 完成上面所有步骤后,就可以通过开发工具将设计的数字电路目标文件下载到 FPGA/CPLD 芯片中,然后在电路板上进行调试、验证。 如果要在 ASIC 上实现,则需要制造芯片。一般芯片制造时,也需要先在 FPGA 板卡上进行逻辑功能的验证。
FPGA&ASIC
刘航宇
4年前
0
375
1
GNURadio-软件无线电入门教程
摘要本文介绍了GNU Radio软件无线电框架,包括其概述、工作原理、安装配置以及使用GNU Radio Companion进行流程图创建。文章详细讲解了如何使用GRC进行信号处理模块的搭建和调试,并提供了实际操作示例。关键词:GNU Radio, 软件无线电, 数字信号处理, SDR, GNURadio Companion目录 第一章 GNURadio 和软件无线电概述1.1什么是 GNU Radio 1.2为什么我们要使用 GNU Radio 1.3关于数字信号处理 1.4GNU Radio 是如何工作的 第二章 GNU Radio 软件安装与配置2.1操作系统的选择 2.2Linux 环境下的直接安装 2.3Linux 下使用PyBOMBS 辅助自动从源码构建 2.4Linux 下手动从源码编译构建请参阅: 2.5Windows 环境下的安装 2.6Mac OS X 环境下的安装 第三章 教程初阶3.1熟悉使用 GNU Radio Companion 第一章 GNURadio 和软件无线电概述 1.1什么是 GNU Radio GNU Radio 是一个软件框架,使用户能够设计、模拟和部署功能强大的软件无线电系统。它是一个高度模块化的,面向“流程图”的框架,带有一个全面的处理模块库,可以轻松组合并构成复杂的信号处理系统的应用程序。 GNU Radio 已用于大量的无线电应用程序。包括音频处理,移动通信,跟踪卫星,雷达系统,GSM,数字无线电等等,所有这些都在计算机软件中使用。 1.2为什么我们要使用 GNU Radio 以前,在开发无线电通信设备时,工程师必须先开发用于接收并处理特定信号的接收机, 来对特定信号传输进行解码或编码。随着数字信号处理与其算法越来越复杂,这些信号处理的平台也变得越来越复杂,通常需要较为高速的 ADC、FPGA 以及能将实时数据串流到计算机平台的连接芯片等,每个系统所对应的硬件平台不一定是一样的,这就带来了巨大的开发成本。通过使用软件无线电(SDR)设备进行模拟信号处理,在相同的硬件平台上可以同时兼容运行各种不同的软件程序,不仅节约了开发成本,也提高了开发新系统的效率。 1.3关于数字信号处理 作为一种软件框架,GNU Radio 通过硬件平台串流的比特数据流输入到计算机中,并在操作系统中运行相应的应用程序以此达到对特性信号进行处理的目的。 我们都知道计算机只能处理数字信号。如何去理解数字信号呢? 简单举个例子:当你想要录制一段人声的时候,说话的人会产生声音信号,该信号由震动导致周围气压发生变化而产生。这样一个时变的物理量就是一种信号。 图片 当空气波到达麦克风时,麦克风将变化的压力转换为电信号,即可变电压 图片 现在我们已经将信号转化为了电信号,在一些模拟系统中,已经可以开始对信号进行处 理。但是对于我们的计算机系统,一个数字的系统,这还远远不够。为了使计算机能够处理这样的数据,我们还需要满足两个条条件:1.是有限点数的 2.是在有限时间之内的 图片 因此,该数字信号可以由称为样本的数字序列表示。采样之间的固定时间间隔直接影响到采样率。提取物理量(电压)并将其转换为数字样本的过程由模数转换器(ADC)完成。相反,我们还有数模转换器(DAC),可从将计算机中提取数字序列转换为模拟信号。 现在我们已经有了一个数字序列,我们的计算机就可以使用它进行各种操作。 图片 同样,电磁波显然也是一种波,它跟声波有许多相同的性质。我们可以用天线将变化的电信号发射出去,这个电信号一般位于一个较高的频率上,可以是数百 KHz 到 GHz。通过使用软件无线电接收机,我们可以接收并对这些信号进行处理,以此进行我们想要的操作。 1.4GNU Radio 是如何工作的 在 GNU Radio 中,为了处理数字信号,我们可以使用简单的流程指示箭头将其连接: l1psgx5b.png图片 在上图中,Signal Source 即为信号源,左边的输入接口可以输入频率参数,右边的输出接口可以输出音频数据流。右边的 Audio Sink 为音频接收器,允许通过扬声器或其他音频设备播放出输入的信号。这就构成了一个十分简单的流程图,点击软件中的运行按钮即可非常简单快捷的编译流程图并运行。 GNU Radio 是一个框架,用于开发这些处理模块并创建流程图。软件自带大量的处理模 块,在这里简单举例一些: Waveform Generators 信号发生器 Constant Source 常数源(可以理解成直流分量) Noise Source 噪声源 Signal Source (e.g. Sine, Square, Saw Tooth) 信号源 Modulators AM Demod AM 解调 Continuous Phase Modulation 连续相位调制 PSK Mod / Demod PSK 调制/解调 GFSK Mod / Demod GFSK 调制/解调 GMSK Mod / Demod GMSK 调制/解调 QAM Mod / Demod QAM 调制/解调 WBFM Receive 宽带 FM 接收机 NBFM Receive 窄带FM 接收机 使用这些模块,我们只需要进行相应的连接操作,就可以快速搭建数字信号处理系统。另外,当然你也可以自己开发新的 block,或者将现有的块与其他软件结合在一起,开发出新的功能。 因此,GNU Radio 主要是用于开发信号处理模块及其交互的软件框架。它带有广泛的标准块库,开发人员可以在其中构建许多系统,是十分方便的软件无线电开发工具。 第二章 GNU Radio 软件安装与配置 GNURadio 的官方 GitHub 页面为 https://github.com/gnuradio/gnuradio。其首页中也明确说明了对于不同操作系统的不同安装方式。 2.1操作系统的选择 我个人最推荐使用 Ubuntu18.04 我在这个系统版本上搭建过很多次所需要的环境,没怎么出过问题,使用一直很稳定。19 版本或许可以,我没有尝试过,但是 20 版本一定不可以, 因为有接到过软件报错的情况报告。 2.2Linux 环境下的直接安装 对于GNU Radio,如果只是简单轻度使用我就建议大家直接使用 Linux 的二进制软件包安装。最快捷方便而且最重要不容易出错。根据 GNURadio 官方 GitHub 界面,首先的安装方式也是直接使用 apt 安装。 以下命令适用于 Debian,Ubuntu 及其衍生版本。它将使用 Python2 安装 GNURadio 3.7 版 sudo apt install gnuradio 对于以上操作系统,直接执行这条命令即可安装完成。如果遇到报错建议自行查询报错信息解决。对于其他 Linux 发行版,请查阅: https://wiki.gnuradio.org/index.php/InstallingGR#From_Binaries 2.3Linux 下使用PyBOMBS 辅助自动从源码构建 PyBOMBS 是安装GNURadio 以及相关软件工具的一个快捷工具。你可以使用它来安装各种 SDR 设备所依赖的支持库,绝大部分操作都是全自动的。 PyBOMBS 是方便用来从源代码构建 GNU Radio,UHD 和各种 Out of Tree(OOT)模块,然后将其安装到指定的用户目录中的工具。在使用之前,PyBOMBS 会检测用户的操作系统并在构建的第一阶段加载所有先决条件(可能会出现各种花式报错)。如果你对于自己解决 Linux 环境配置问题不是很有信心,我不建议你使用这种方法安gnuradio。 注意!!:GitHub 中详细描述了安装的步骤,请自行参阅: 项目地址:https://github.com/gnuradio/pybombs 因为它是从源代码安装GNU Radio,所以第五步可能需要一些时间,要进行更快的安装, 请参阅 https://wiki.gnuradio.org/index.php/InstallingGR#Ubuntu_PPA_Installation 2.4Linux 下手动从源码编译构建请参阅: https://wiki.gnuradio.org/index.php/InstallingGR#From_Binaries 2.5Windows 环境下的安装 在 Windows 环境下,官方提供了非正式版的 GNU Radio 3.7 和 3.8 的安装文件,虽然我也不推荐你真的在 Windows 平台运行这个软件,但是它在 Win 平台是真的可以使用的。不管是 USRP 还是 PlutoSDR,有驱动程序的话就可以使用。对于 USRP,可能存在固件版本的问题,按照教程后面的解决办法是可以解决的。 相关的安装软件包在这里下载:http://www.gcndevelopment.com/gnuradio/index.htm 2.6Mac OS X 环境下的安装 你是认真的? 请参阅:https://wiki.gnuradio.org/index.php/MacInstall 第三章 教程初阶 3.1熟悉使用 GNU Radio Companion 学习目的: 使用标准块库创建流程图 了解如何使用检测模块 Sink 调试流程图 了解GNU Radio 中的采样和调节功能 了解如何使用文档找出模块的功能 在本教程中,我们将从简单框图开始,探讨如何使用 GNU Radio 的图形工具GNU Radio Companion(GRC)来创建不同的框图。GRC 是为了简化 GNU Radio 而诞生的,有了它, 我们可以以图形化编程的方式创建 python 脚本,替代了传统的复杂代码编写,进而降低软件无线电编程的入门门槛。 那么我们开始。首先打开终端,输入以下指令。 $ sudo gnuradio-companion或者直接单击软件图标,也是可以运行软件的。 图片 如果你发现不仅应用程序中没有出现软件图标,而且终端也不能打开这个软件,那么你的安装很有可能出现了问题。请检查安装是否存在问题。 这里有一点区别。当你通过终端运行 GRC 时,下图绿色部分的终端会同时在系统终端里显示。而如果直接通过点击软件图标运行则只能在GRC 的终端面板中观察信息。 图片 首先我们来介绍软件界面。总共分为五个部分:库,工具栏,终端,工作区和变量。 红色区域为工具栏部分,放置了平时最常用的工具,比如运行、停止、编译等重要功能按键。 l1psl5it.png图片 新建、打开、保存、关闭 l1q067qo.png图片 打开/关闭变量编辑器、截图、剪切、复制、粘贴、删除选中模块 l1q06j9q.png图片 查看错误信息、编译流程图、执行流程图、停止运行流程图 l1q06to8.png图片 撤销、重做 l1q074k2.png图片 启用选中模块、禁用选中模块、绕过选中模块、反转禁用连接/模块的状态 l1q07e6n.png图片 查找模块、重置模块、打开选中阶梯模块源码 蓝色区域即为我们绘制具体流程图的地方。我们可以将右边灰色部分库中的模块拖入蓝色区域,并且将他们通过箭头连接起来,这样就可以构成一个真正的信号处理系统。 黄色部分显示的是当前框图中所使用到的变量。在蓝色部分的左上角可以看到两个方框, 分别是 Options 与 Variable,这两个是创建工程时就会自动创建的。 在界面的右边灰色区域中,存放了大量可以用于拖拽到流程图中的模块。其中有很大一部分是软件安装时就自带的,如果你安装了其他gnuradio 附属的插件脚本,也会一并显示在框中,通常自行安装的会显示在最后面。 图片 因为模块非常多,因此平时寻找想要的模块时一个一个手动翻找会非常麻烦。此时可 以点击工具架上的放大镜图标,或是输入 Ctrl + f 输入该块的关键字进行检索,就可以更容易的找到这个block。 例如,这里我们输入 sink(接收器),就可以看到包含单词“接收器”的所有块以及将在其中找到每个块的类别。 l1q08cz9.png图片 现在,我们来添加一个名为 QT GUI Time Sink 的块,方法是单击其名称并将其拖动到工作区中,或者双击其名称以将其自动放置在工作区中。 图片 工作区包含构成流程图的所有块,在每个块内部都有不同的块参数,但是,每个新流程图都需要有一个特殊的块,称为“选项块”。让我们双击选项块以检查其属性。 双击opthions 模块可以看到它的具体内容。Options 中包含了工程的特殊参数设置,每个流程图仅允许存在一个这样的选项模块。 图片 上面的 ID,title,author,description,分别表示这个流程图的 ID,标题以及作者和简介。该块的 ID 决定了生成文件的名称和类的名称。例如,一个 ID 为 top_block 的文件将生成文件 top_block.py 和 top_block 类。 Cavans Size 窗口大小控制流程图编辑器的尺寸。窗口大小(宽度,高度)必须介于 (300,300)和(4096,4096)之间。 Generate options 生成选项控制生成的代码的类型。非GUI 流程图应避免使用带有GUI 的组件或图形变量控件。 Run:流程图的运行可由变量控制,以在需要时启动和停止流程图。 Max number of output 最大输出数是流程图中任何方框所允许的最大输出项数;要禁用此功能,将max_nouts 设置为 0 即可。使用此功能可以调整流程图可以显示的最大延迟。 可以注意到另一个关键的东西。我们可以输入信息的字段中存在的不同颜色。这些实际上对应于不同的数据类型,我们将在本教程的后面部分介绍这些数据类型。 GRC 将我们在编辑器中创建的流程图转换为Python 脚本。因此当我们执行流程图时, 实际上是在运行编译好的Python 程序。ID 用于命名该 Python 文件,该文件与.grc 文件保存在同一文件夹内。默认情况下,ID 是默认值,因此它将创建一个名为 default.py 的文 件。更改 ID 可让我们更改保存的文件名,以便更好地管理文件。在 GNUradio 3.8 中,如果不更改默认 ID,则会收到错误消息,因此需要更改此 ID 才能运行流程图。 l1q0acje.png图片 Variable 即变量,它的 ID 是 samp_rate,你可以在框图中的其他地方调用这个变量。 例如: l1q0amjo.png图片 这样这里的数值就会随着该变量的变化而变化。 如果你点进了设置面板的第三个选项卡,就能看到有关这个block 的文档。通常情况下正规的 block 都是会写使用文档的,当然少数自定义的模块可能是没有的。 虽然这些说明是英文的,但是我十分建议大家自己去用谷歌等工具翻译一下这些文档,因为教程不可能每个详细的点都能讲到,有时还是得靠自己查一查的。 l1q0b5kp.png图片 如果我们删除了一个重要的参数,或是填入了什么不正确的参数,以至于我们的框图无法正常运行,那么此时你会看到执行按钮变成灰色不可点击的状态。此时报错信息按钮亮起,并且在出现错误的block 上,它的名称出现了红色的高亮显示。 l1q0bis5.png图片 你可以点击这个按钮,就可以看到存在问题的错误信息。 l1q0bsmb.png图片 在错误信息中,详细指出了错误出现的位置(如果看不懂就用翻译工具翻译一下,不过英语这么差我建议你直接放弃,这玩意高中生都能看懂。#日常劝退)我们只需要按照报错信息所提示的位置:模块-top block-选项中的一个参数:max_nouts l1q0c3uy.png图片 双击打开这个模块,就可以看到在模块中也存在同样的错误信息提示位于正下方。 l1q0cmos.png图片 错误明确指出,在这个输入框中数值“”不能被接受,因为这里必须填写的是一个数字, 我们填写数字 0 进去后点击确定,即可发现错误信息已经消失。执行按钮也亮起,说明框图无明显错误,可以正常运行。 现在,我们对如何找到块,如何将它们添加到工作区以及如何编辑块属性有了更好的了解,下面我们随意以几个 block 组成一个框图来进行简单的演示。 刚才我们拖入了 QT GUI Time Sink 这个模块,这是个图形接收器,可以同时显示多个信号。接下来我们搜索并向流程图中添加 Signal Source(信号源)模块,和 Throttle(节气门)模块,有关这几个模块详细的说明将在之后的教程中详细讲解,现在只需知道此块会限制流程图的某些数据即可,以确保它不会占用 100%CPU 资源导致电脑直接卡到裂开。 l1q0daor.png图片 “生成流程图”,“ 执行流程图”和“终止流程图”的快捷键分别为 F5,F6 和 F7。你可以在我们刚刚提到的工具架上点击这些按钮,或者直接按快捷键来进行相关的操作。当你按下生成流程图按钮之后,软件就会自动将你刚才绘制的流程图转化为一个 python 脚本文件。单击执行流程图按钮之后,就可以看到以下运行结果。 l1q0dl85.png图片 如果你不想运行了,只要点击终止流程图即可停止当前运行的程序。这样我们的第一个流程图就成功运行了。这是一个从信号源产生信号,经过限流器限制后输出到 time sink 进行接收并显示到屏幕上的操作。 你可以注意到这里有两根数据曲线被绘制出来,他们都来自于 Data 0,蓝色的曲线为Re(实部),红色部分为 Im(虚部)。 如果你根本不知道Re 和 Im 是什么个玩意儿,那么我建议你先学习下我们电子通信类专业的一门必修课程《复变函数》,这将会对你的系统性学习产生很大的帮助。 l1q0e32p.png图片 (有意思的是这两个信号的相位差正好为 ,这对于我们的零中频(Zero-IF)接收/发 2 射机有至关重要的意义,不过这个咱们以后有机会再提。) 在这个流程图中,我们很轻松的就把所有的block 连起来了,轻松的离谱你不觉得吗? 没有出现任何头疼的问题或是错误。那么有没有会出现错误的情形呢?当然有,而且经常会有。 Source IO size "8" does not match sink IO size "4". 源 IO 大小“ 8”与接收器 IO 大小“ 4”不匹配。 这似乎是一个和数据类型有关的报错。既然出现了这个错误,那么就说明我们还没有搞懂框图输入输出的数据类型到底是个什么玩意儿。那么现在就让我们点击软件上方的 help,这里面有对于数据类型的说明。 图片 图片 (最上面那个棕色的看的不是很清楚,不过这问题不大,你用鼠标把它选中高亮就能看清了。) 我们可以看到在许多编程语言中都可以看到的常见数据类型。在我们刚才搭建的流程图中,你可以注意到所有连接的模块端口均是蓝色的,这代表当前所传输的数据为Complex Float 32 类型,这意味着它们同时包含实部和虚部,并且每一个都是 Float 32 类型。我们可以推断出,当“Time Sink 时间接收器”采集到这样一个Complex 的数据类型时, 它将在两个不同的通道上同时输出实部和虚部的图像,也就是我们刚才看到的红蓝两种颜色的图像了。 现在进入其 Signal Source 的属性面板,并更改“输出类型”参数,将信号源更改为浮点型输出。此时我们传输的数据流是一个普通的 32 位浮点数。 图片 图片 可以看到现在我们所有连接的点均变成了橘色,(当然 throttle 也要调整,别问我为什么它还是蓝色的),这也就说明了目前数据类型均匹配,当然刚才出现的报错也就消失了。 图片 有同学发现 throttle 的输出连接了两个 block。不同的节点之间是可以支持多条同样的数据链路的,这是非常方便的一点,也是绝大部分图形化编程界面都具有的功能。可以注意到刚才的两条线此时变成了只有一条线,这是因为我们刚刚修改了数据类型。 现在让我们来尝试一些更复杂的框图吧。 图片 运行结果如下: 图片
通信&信息处理
# 软件无线电
刘航宇
4年前
0
6,128
6
2022-03-30
西北大学843&849备考小经验
摘要本文分享了作者备考西北大学电子科学与技术专业的经验,包括英语、政治、数学和专业课的学习方法,强调真题的重要性,并提供了免费笔记资源。关键词:西北大学, 843备考, 849备考, 考研经验, 电子科学与技术目录 843&849历年真题 下载地址:https://wwu.lanzoub.com/i3si90ai9k3g 提取码: 正文 本人22考研已经上岸西北大学电子科学与技术专业 图片 本文不会长篇大论,节省彼此时间,不建议天天看经验贴,有这时间建议做个题跑个步比啥都好。 英语和政治篇 英语和政治篇不多叙述、我相信这个难不倒大家,过线肯定能过,多年国家线分数线尚未超过40,精简回答政治7、8月起每天1-2小时,英语前期单词后期真题,真题建议做到2刷。 数学篇 本人数学这次没发挥好105分,,本人正式备考在7月份开始考研,时间短,那么这么短时间如何提高数学与专业课呢?答案就是不断做题,看视频是次要的本人由于起步晚,直接不看视频就做题,不会就翻书查答案,再不行就看对应知识点,一下节省了好几个月时间。咳咳,不建议大家学我。数学前期建议选任何一本考研书都可,1800不建议因为答案非最简答案,很多同学看不懂原因是这个思路有问题,不是最简思路,并非见到极限我就用泰勒!9月前完成强化,强化方式1.强化卷、2.题目少的习题册(张、汤、李都有)选一个精做,别欺骗自己只求数量、不求质量那是害人!9月-10月先做各机构的模拟题,先不要做真题,模拟题做多少是多少!10月-12月中旬做真题,数一必须后期真题,真题每年有好多以前考过的类型你在二刷时候就能发现22年、21年、20年、19年等等都有很多和19xx年、200x年很类似题目,千万别后期光刷模拟题质量不是一个层次哦!第一个月2天1张卷子第一天做完第二天改错吃透,第二个月1天1份,最后半月二刷1天2份根据程度只刷错题也行一定一定要吃透!历年真题。。我们偶数年吃透考个100+不是问题,奇数年吃透110+不是问题。数学就是题海战术和反复吃透,真题很重要有可能就从1987年起刷2次,真题错题能做到我遇到必会就是一个反反复复克服定势思维的过程。 专业篇 不要迷信押题卷,我们这一届843、849也没几个报班、还有有些微博网上讲题的老师水平,emmm我不评价!? ,我考研期间都 免费 给别人讲了一些题,我相信学弟学妹应该也需要学习那么就挂出来吧,如下所示 集成运放深度理解讲解 专业课如何学? 1.前期(7、8月左右)看上海交大模电视频、认真做笔记,有空课后题 2.数电呢?数电再模电之后学、数电可以看书自学23456章很重要,课后题必做,比如逻辑代数,编码、译码器,寄存器,计数器,加法器这些等等 视频课后题9月中旬前建议完成 3.后期9月中旬后,建议好好研究真题?学长可以免费提供我的个人笔记 4.真题建议做到二刷、吃透,最后1个月看自己笔记和书本和做过的习题即可,基本没有什么大问题的 迷茫指导 结语 西北大学很好,老师也很强,希望各位学弟学妹都能上岸,加油!考研过程最忌讳形式主义、自我感动,合理规划,适合自己是最总要的,我的仅仅是个提示,不要老是看这些,7月前有时间多多锻炼一下身体,西北大学目前843、849在211考研中难度不是很大,既然选择了认真对待肯定没问题!学长希望大家都能上岸,一战成硕! 免费笔记入口 模拟电子技术 数字电子技术
我的随笔
刘航宇
4年前
0
1,302
15
SIM900A发送与接受短信
摘要本文介绍了使用SIM900A模块实现短信的收发,包括Text Mode和PDU Mode两种控制模式,以及GSM编码和UCS2编码的使用。详细说明了如何通过AT指令进行短信的发送和接收,包括英文和中文短信的发送方法。关键词:SIM900A, 短信服务, SMS, Text Mode, UCS2编码目录 一.SMS简介 二.短信的控制模式与编码1.Text Mode 2.PDU Mode 3.GSM编码 4.UCS2编码 三.收发英文短信1.AT+CPMS查询短信数量 2.AT+CNMI设置新消息提示类型 3.AT+CMGF选择短信模式 4.AT+CSCS设置编码 5.AT+CSMP设置短信文本模式 6.AT+CMGS发送消息到指定手机号 四.收发中文短信 一.SMS简介 SMS(Short Messaging Service)中文名称短信服务,短信是当下每一部手机上必备的功能之一,顾名思义,它是在手机之间发送文字信息或从个人计算机或手持设备向手机发送信息的一种方式,其文本信息的最大发送量为160个字符(字母、数字或者拉丁字母中的字符),对于中文一般最大发送量为70个字符。 这里我想用SIM900A模块实现短信的收发。 图片 二.短信的控制模式与编码 先说一下:我采用的是Text Mode下使用GSM编码收发英文短信、使用UCS2编码收发中文短信 对于短信的控制一共有三种模式:Block Mode、基于AT指令的Text Mode、基于AT指令的PDU Mode 。目前手机中默认使用PDU Mode,通过PDU编码的短信可以是文字、声音或者图像。Text Mode只能用于发送ANSI范围的字符,发送方式比较简单。 SIM900A模块只提供Text Mode 和PDU Mode。 中文短信中,所有汉字和字符都是采用UNICODE编码。 1.Text Mode Text Mode下,发送及接收到的数据均以ASCII码的显示来表示,可以发送指令"AT+CMGF=1",将GSM短信发送方式更改为文本模式。文本模式下接收的数据会自动解码,比如你收到一条短信息,GSM会返回:+CMGR: “REC UNREAD”,"+8613806XXXXXX",“11/10/21,13:22:13+32” hello (短信内容会自动换行) 不需要自己解码,便可得到短信的发送者、发送时间和短信内容,比较容易操作。 理论上Text Mode下,是只能够收发英文短信,但是SIM900A模块可以在Text Mode下使用UCS2编码,从而可以发送接收中文短信。 2.PDU Mode PDU相当于一个数据包,它由SMS的信息组成,作为一种数据单元,必须包含源地址、目的地址、有效时间、数据格式、协议类型、正文、正文长度(可达140字节),这些信息都以十六进制表示。 PUD Mode被所有手机支持,可以使用任何字符集,其编码方式分为:7bit、8bit、UCS2。 7-bit编码用于发送普通的ASCII字符,它将一串7-bit的字符(最高位为0)编码成8-bit的数据,每8个字符可“压缩”成7个;8-bit编码通常用于发送数据消息,比如图片和铃声等;而UCS2编码用于发送Unicode字符。在这三种编码方式下,PDU串的用户信息(TP-UD)段最大容量(可以发送的短消息的最大字符数)分别是160、140和70。这里,将一个英文字母、一个汉字和一个数据字节都视为一个字符。 理论上发送中文短信需要使用PDU Mode的UCS2编码,上面也说了,SIM900A模块可以使用Text Mode发送UCS2编码,而且PDU Mode比Text Mode更加复杂,所以我采用了Text Mode收发中英文短信。 PDU Mode的详细讲解可以借鉴此博客:点击链接跳转 3.GSM编码 在GSM编码模式下,收发消息的内容和电话号码,都是以ASCII字符的形式显示的,发送英文短信时使用十分方便。 所以我使用GSM编码来收发英文短信。 4.UCS2编码 谈到UCS2编码就不得不说UNICODE,UNICODE又叫统一码、万国码,是计算机科学领域里的一项行业标准,包括字符集、编码方案等。UNICODE 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。简单来说,UNICODE编码可以表示世界上任意一种语言(有点夸张),自然也可以表示中文。 而UCS2编码是UNICODE的一种,UCS2中每个字符都占俩个字节。 使用UCS2编码后,发送短信的手机号码、短信内容都要经过UCS2编码转换才可以,但UCS2编码发送的消息在手机上可以直接显示为中文。 所以,需要UCS2与中文的转换软件,如下,可以实现中文和UCS2的双向转换 图片 三.收发英文短信 1.AT+CPMS查询短信数量 图片 2.AT+CNMI设置新消息提示类型 图片 3.AT+CMGF选择短信模式 图片 4.AT+CSCS设置编码 图片 图片 5.AT+CSMP设置短信文本模式 使用Text Mode的GSM编码时,短信文本模式设置为: AT+CSMP=17,167,0,240(消息显示在终端) AT+CSMP=17,167,0,241(消息存储在SIM卡中) 图片 6.AT+CMGS发送消息到指定手机号 使用Text Mode的GSM编码时,直接AT+CMGS="手机号"即可,然后,在>后输入要发送的内容(不要勾选发送新行),最后发送HEX(十六进制)的:1A 即可。 如图,我使用本机向本机发送了一条短信,而且,本机收到短信后在终端中显示出来了。 图片 这是SIM公司给出的例子: 图片 CTRL-Z 代表十六进制:1A 使用SIM900A向本机发送一条英文短信的完整步骤如下: 图片 四.收发中文短信 收发中文短信利用的是Text Mode下的UCS2编码。 相比于收发英文短信,收发中文短信需要修改的地方有: 修改编码:AT+CSCS=“UCS2” 修改短信文本模式:AT+CSMP=17,167,0,24(短消息显示在终端,25:存储在SIM中) 手机号码要用UNICODE码 发送的消息要用UNICODE码(有专门的转换软件) 这是SIM公司给出的例子: 图片 我要发送信息:可爱的小白鼠,女朋友收到后回复消息,用软件将UNICODE码转换为中文,串口操作界面如示: 图片 发消息如示: 图片 收消息如示: 图片 这是我的SIM900A 图片
嵌入式&系统
刘航宇
4年前
0
1,264
2
2022-01-29
【9】基于STM32CubeMX-STM32OLED开发
摘要本文介绍了基于STM32CubeMX-STM32OLED的开发过程,包括OLED概述、驱动函数库移植、常用函数介绍以及实训案例,展示了如何使用STM32控制OLED显示图片和信息。关键词:STM32CubeMX, OLED, STM32, 驱动程序, 显示开发目录 必备文件 关于OLED的概述 OLED开发相关资源下载 基于STM32CubeMX的OLED底层驱动函数移植 OLED驱动库中常用的函数 实训案例:STM32控制OLED显示 必备文件 必备文件 见文章末尾 关于OLED的概述 OLED:Organic Light-Emitting Display,有机发光显示。 OLED具备自发光、厚度薄、视角广、功耗低、对比度高、响应速度快、可用于挠曲性面板、使用温度范围广、构造及其制作过程较简单等优异特性,并认为是一种比液晶显示更为先进的新一代平板显示技术。以目前的技术,OLED的尺寸还难以大型化,但是分辨率却可以做得很高。 基于STM32的OLED应用,要做那些事情: 【1】移植OLED的底层驱动函数库。 【2】准备需要的中文字符和图片等数据。 【3】调用OLED驱动库中的底层函数进行应用开发。 图片 OLED开发相关资源下载 基于STM32CubeMX的OLED屏驱动程序库(内含4个文件) 【1】XMF_OLED_STM32Cube.c:驱动程序的源文件。 【2】XMF_OLED_STM32Cube.h:驱动程序的头文件。 【3】XMF_OLED_Font.h:字库数据文件。 【4】XMF_OLED_BMP.h:图片数据文件。 基于STM32CubeMX的OLED底层驱动函数移植 【1】将4个驱动文件拷贝到工程文件中,和main.c放在同一目录,并将XMF_OLED_STM32Cube.c添加到工程代码文件中,并在main.c中引入头文件XMF_OLED_STM32Cube.h。 【2】根据所选用的芯片型号,修改XMF_OLED_STM32Cube.h头文件中所以用的芯片头文件。 【3】根据硬件电路原理图中,修改XMF_OLED_STM32Cube.h中OLED的引脚定义。 【4】查看OLED_Initvoidvoidvoid初始化函数的源码,根据电路接口和应用需要进行修改。 图片 OLED驱动库中常用的函数 void OLED_Init(void); //OLED初始化函数 void OLED_Clear(void); //OLED清屏函数//显示英文字符串函数 void OLED_ShowString(unsigned char x,unsigned char y,unsigned char *p); 参数1:x,起点列坐标,0~127 参数2:y,起点行坐标,0~7 参数3:*p,字符串指针 返回值:void,无。//显示中文字符函数 void OLED_ShowCHinese(unsigned char x,unsigned char y,unsigned char no); 参数1:x,起点列坐标,0~127 参数2:y,起点行坐标,0~7 参数3:no,待显示中文字符在数组Hzk[][32]中的位置。 返回值:void,无。//显示图片函数 void OLED_DrawBMP( unsigned char x0, unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]); 参数1:x0,起点列坐标,0~127 参数2:y0,起点行坐标,0~7 参数3:x1,图片的列范围,1~128 参数4:y1,图片的行范围,1~8 参数5:BMP[],待显示图片数据的数组。 返回值:void,无。实训案例:STM32控制OLED显示 要点 图片 字库软件中行前后缀不需要括号 在XMF07A或XMF07C开发板上,利用STM32CubeMX和Keil5协同开发,完成以下的功能: 【1】用取字模软件生产一张图片数据,作为开机界面在OLED上显示。 【2】0.5秒后进入信息界面, 第1行显示网址“sciarm.com”, 第2行显示中文“小蜜蜂笔记”,第3行显示日期“2022-02-18”。 图片 //用取字模软件生成开机LOGO图片数据,并拷贝到XMF_OLED_BMP.h的数组中。 const unsigned char BMP1[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //此处省略64×62个字节元素 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, };//用取字模软件生成所需中文字符数据,保持到XMF_OLED_Font.h中的Hzk[]数组。 const unsigned char Hzk[][32]={ {0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x20,0x40,0x80,0x00,0x00}, {0x08,0x04,0x03,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,0x01,0x0E,0x00},/*"小",0*/ /* (16 X 16 , 宋体 )*/ {0x10,0x4C,0x24,0x04,0xF4,0x84,0x8D,0x56,0x44,0x24,0x14,0xC4,0x24,0x54,0x0C,0x00}, {0x00,0x41,0x5D,0x55,0x54,0x55,0x55,0x7F,0x55,0x55,0x55,0x55,0x7C,0xC0,0x00,0x00},/*"蜜",1*/ /* (16 X 16 , 宋体 )*/ {0x00,0xF8,0x08,0xFF,0x08,0xF8,0x80,0x90,0x4C,0x57,0xA4,0x54,0x4C,0x84,0x80,0x00}, {0x20,0x63,0x21,0x1F,0x11,0x39,0x10,0x10,0x15,0x15,0xFF,0x15,0x15,0x10,0x10,0x00},/*"蜂",2*/ /* (16 X 16 , 宋体 )*/ {0x10,0x08,0x44,0x47,0x4C,0x54,0x44,0xD4,0x28,0x27,0x24,0x2C,0x34,0x04,0x04,0x00}, {0x00,0x10,0x12,0x12,0x12,0x12,0x12,0x7F,0x89,0x89,0x89,0x89,0x89,0x88,0xF0,0x00},/*"笔",3*/ /* (16 X 16 , 宋体 )*/ {0x40,0x40,0x42,0xCC,0x00,0x00,0x00,0x84,0x84,0x84,0x84,0x84,0xFC,0x00,0x00,0x00}, {0x00,0x00,0x00,0x7F,0x20,0x10,0x00,0x3F,0x40,0x40,0x40,0x40,0x41,0x40,0x70,0x00},/*"记",4*/ /* (16 X 16 , 宋体 )*/ };extern unsigned char BMP1[]; void OLED_display_pic() { OLED_Clear(); OLED_DrawBMP(0,0,128,8,BMP1); }void OLED_display_info() { OLED_Clear(); OLED_ShowString(6,0,(uint8_t *)"sciarm.com"); OLED_ShowCHinese(10,3,0); //小 OLED_ShowCHinese(28,3,1); //蜜 OLED_ShowCHinese(46,3,2); //蜂 OLED_ShowCHinese(64,3,3); //笔 OLED_ShowCHinese(82,3,4); //记 OLED_ShowString(24,6,(uint8_t *)"2022-02-18"); }//在mian()函数中添加下面的代码: /* USER CODE BEGIN 2 */ OLED_Init(); //OLED初始化 OLED_display_pic(); //显示图片 HAL_Delay(500); //延时0.5秒 OLED_display_info(); //显示信息 /* USER CODE END 2 */必备文件
嵌入式&系统
# 嵌入式
刘航宇
4年前
17
2,159
15
【7】基于STM32CubeMX-STM32ADC模数转化基本原理
摘要本文介绍了STM32CubeMX-STM32ADC模数转换的基本原理,包括ADC概述、技术指标、基本转换过程,并通过实训案例展示了ADC数据采样的计算应用。关键词:STM32CubeMX, STM32ADC, 模数转换, ADC技术指标, 温度测控系统目录 模数转换器(ADC)概述 ADC的几个技术指标 剖析ADC的基本转换过程 实训案例:ADC数据采样的计算应用 模数转换器(ADC)概述 ADC:Analog-to-Digital Converter 将时间和幅值连续的模拟量转化为时间和幅值离散的数字量,A/D转换一般要经过采样、保持、量化和编码4个过程。 常用ADC:逐次逼近型、双积分型、∑-Δ型。 图片 ADC的几个技术指标 【1】量程:指ADC所能输入模拟信号的类型和电压范围,即参考电压。信号类型包括单极性和双极性。 【2】转换位数:量化过程中的量化位数n。 A/D转换后的输出结果用n位二进制数来表示。 【例】:10位ADC的输出值就是0~1023。 【3】分辨率:ADC能够分辨的模拟信号最小变化量。计算公式是,分辨率 = 量程 / 2的n次方 【例】:量程为单极性0-5V,8位ADC的分辨率是,5 / 256 = 0.0195V 【4】转换时间:ADC完成一次完整的A/D转换所需要的时间,包括采样、保持、量化、编码的全过程。 剖析ADC的基本转换过程 图片 实训案例:ADC数据采样的计算应用 有一个温度测控系统,已知温度传感器在0到100度之间为线性输出,参考电压为5V,采用8为的A/D转换器,0度的时候,测的电压为1.8伏,100度的时候,测的电压为4.3伏。 【问题1】:系统的分辨率是多少? 【问题2】:采集到数据10010001,表示多大电压?温度是多少? 由于温度是线性变化,先求得斜率k,得到温度和电压的关系表达式。 k = (100 – 0)/(4.3-1.8) = 40, y = 40*(x-1.8) (x为采样得到的电压) 由于采用的是8为ADC,参考电压为5V,所以分辨率为: 5 / 256 = 0.0195V = 19.5mV(最小能分辨的电压,分辨率) 0.0195 * 40 = 0.78度(最小能分辨的温度) 因为 10010001B = 91H = 145(16x9+1), 所以 0.0195 * 145 = 2.8275V 该电压信号对应的温度是:(2.83V – 1.8V) * 40 = 41.1摄氏度
嵌入式&系统
# 嵌入式
刘航宇
4年前
0
1,127
14
2022-01-17
【3】基于STM32CubeMX-STM32中断系统
摘要本文介绍了STM32中断系统,包括中断概念、STM32中断源、中断向量、中断优先级等基础概念,并详细阐述了STM32外部中断的设计步骤和程序编写方法,最后通过实训案例展示了如何利用STM32CubeMX和Keil5实现外部中断控制LED灯开关。关键词:STM32CubeMX, STM32中断系统, 外部中断, NVIC, GPIO中断目录 中断什么意思 STM32的中断系统 STM32的外部中断 外部中断的程序设计思路 外部中断初始化函数剖析 外部中断服务函数的编写 实训案例:外部中断信号控制LED灯开关 中断什么意思 你打开火,烧上一壶水。然后去洗衣服,在洗衣服的过程中,突然听到水壶发出水开的报警声,这时,你停止洗衣服动作,立即去关掉火,然后将开水灌入暖水瓶中,灌完开水后,你又回去继续洗衣服。这个过程中实际上就发生了一次中断。 如图: 图片 图片 STM32的中断系统 理解中断、中断源、中断向量、中断优先级、中断服务函数…等基础概念。 ARM Cortex M3内核支持256个中断,包括16个内核中断和240个外设中断,拥有256个中断优先级别。 STM32的中断通道可能会由多个中断源共用。这就意味着,某一个中断服务函数也可能被多个中断源所共用。所以,在中断服务函数的入口处,需要有一个判断机制,用以辨别是那个中断触发了中断。 STM32微处理器的内核中有一个NVIC(嵌套向量中断控制器)的设备,它对中断进行统一的协调和控制,其中最主要的工作就是控制中断通道的使能和确定中断的优先级。 STM32中有2个优先级的概念:抢占优先级和响应优先级,每个中断都需要指定这两种优先级。 如果两个抢占优先级相同的中断同时到达,NVIC会根据他们的响应优先级高低来决定先处理哪一个。如果两个同时到达的中断的抢占优先级和响应优先级都相等,则根据中断的自然排位顺序来决定响应哪一个。 STM32的外部中断 外部中断EXTI是STM32微处理器实时处理外部事件的一种机制,由于中断请求主要来自GPIO端口的引脚,所以称为外部中断。 STM32F013微处理器有19个能产生事件/中断请求的边沿检测器,每个输入线可以独立地配置成输入类型(脉冲或挂起)和对应的触发事件(上升沿、下降沿或双边沿触发),也可以独立地屏蔽。 EXTI0~EXTI15:GPIO端口引脚。 EXTI16:PVD输出,可编程电压监测。 EXTI17:RTC闹钟。 EXTI18:USB唤醒。 外部中断的程序设计思路 传统STM32外部中断设计步骤 : 【1】将GPIO初始化为输入端口。 【2】配置相关I/O引脚与中断线的映射关系。 【3】设置该I/O引脚对应的中断触发条件。 【4】配置NVIC,并使能中断。 【5】编写中断服务函数。 配置要点提示 引脚设外部中断,上升沿,上拉 图片 使能NVIC 图片 基于STM32CubeMX的外部中断设计步骤: 【1】在STM32CubeMX中指定引脚,配置中断初始化参数。 选择GPIO引脚的功能,设置中断信号触发条件,使能NVIC对应的中断通道。 【2】重写该I/O引脚对应的中断回调函数。 外部中断初始化函数剖析 //外部中断初始化相关的操作在gpio.c文件中的MX_GPIO_Init()函数完成。 void MX_GPIO_Init(void) { /*===================== 此处省略无关代码。 ======================*/ /* EXTI interrupt init 外部中断初始化*/ HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0); //设置EXIT9~EXIT5中断的优先级 HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); //使能EXIT9~EXIT5中断通道 HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); }外部中断服务函数的编写 图片 实训案例:外部中断信号控制LED灯开关 在XMF07A或XMF07C开发板上, 利用STM32CubeMX和Keil5协同开发, 完成以下的功能: 【1】将KEY2,即PC13设置为外部中断输入,下降沿触发。在中断服务函数中,切换LED1的开关状态。 【2】将KEY4,即PB5设置为外部中断输入,上升沿触发。在中断服务函 数中,切换LED2的开关状态。 图片 //外部中断的初始化函数由STM32CubeMX辅助生成,用户只需要重写中断回调函数。 /* USER CODE BEGIN 0 */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == GPIO_PIN_13) { HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9); } if(GPIO_Pin == GPIO_PIN_5) { HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8); } } /* USER CODE END 0 */
嵌入式&系统
# 嵌入式
刘航宇
4年前
0
1,253
16
2022-01-16
【1】基于STM32CubeMX-STM32GPIO端口开发
摘要本文介绍了STM32CubeMX代码辅助生成工具,讲解了STM32的GPIO端口知识、HAL库函数以及跑马灯实训案例。通过STM32CubeMX配置GPIO端口,实现LED灯的闪烁,并进行了仿真开发。关键词:STM32CubeMX, STM32GPIO, GPIO端口, HAL库函数, 跑马灯目录 STM32CubeMX的声明 protuesSTM32仿真开发板下载 STM32的GPIO端口知识要点 GPIO电平输出HAL库函数 GPIO电平翻转HAL库函数 GPIO初始化函数源码剖析 实训案例:基于STM32CubeMX的跑马灯 仿真开发实例 protuesSTM32仿真开发板下载 STM32CubeMX的声明 【1】STM32CubeMX 是一个代码辅助生成工具,在生成工程代码的同时,根据你的功能选择和配置帮你做了必要的初始化,这也就意味着你不再需要对底层的特殊功能寄存器进行初 始化配置,但是不代表你就可以不去学习 STM32 的基本知识和各个外设的工作原理与参数 特性等。 【2】虽然不再要求你去了解 STM32 底层寄存器的定义,但却要求你要了解由 STM32CubeMX生产的代码内在的逻辑联系以及 HAL 库中的常用函数原型与使用。 【3】STM32CubeMX 的最大好处就是,使开发流程、文件结构、库函数等标准化 protuesSTM32仿真开发板下载 下载方式见文章末尾 STM32的GPIO端口知识要点 GPIO:General Purpose Input & Output STM32芯片最拥有GPIOA、GPIOB…GPIOG等7组端口,每组端口最多拥有Pin0、Pin1…Pin15共16个引脚。 STM32的每个I/O端口都可以自由编程,但I/O端口寄存器必须按32位字被访问。STM32的每个I/O端口都由7个寄存器来控制。 STM32的GPIO端口可以由软件配置成8种模式: 推挽输出、开漏输出、推挽式复用功能、开漏式复用功能; 模拟输入、浮空输入、下拉输入、上拉输入。 GPIO电平输出HAL库函数 void HAL_GPIO_WritePinGPIOTypeDef∗GPIOx,uint16tGPIOPin,GPIOPinStatePinStateGPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinStateGPIOTypeDef∗GPIOx,uint16tGPIOPin,GPIOPinStatePinState; 参数1:GPIOx,端口号,如:GPIOB,GPIOF。 参数2:GPIO_Pin,引脚号,如:GPIO_PIN_9,GPIO_PIN_12。 参数3:PinState,引脚输出状态。高电平----GPIO_PIN_SET;低电平----GPIO_PIN_RESET。 返回值:void,空。 应用举例:向PB8引脚输出高电平。 HAL_GPIO_WritePinGPIOB,GPIOPIN8,GPIOPINSETGPIOB, GPIO_PIN_8, GPIO_PIN_SETGPIOB,GPIOPIN8,GPIOPINSET;GPIO电平翻转HAL库函数 void HAL_GPIO_TogglePinGPIOTypeDef∗GPIOx,uint16tGPIOPinGPIO_TypeDef* GPIOx, uint16_t GPIO_PinGPIOTypeDef∗GPIOx,uint16tGPIOPin; 参数1:GPIOx,端口号,如:GPIOB,GPIOF。 参数2:GPIO_Pin,引脚号,如:GPIO_PIN_9,GPIO_PIN_12。 返回值:void,空。 应用举例:将PA3引脚输出电平翻转。 HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_3);GPIO初始化函数源码剖析 void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO端口时钟使能 */ __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /*配置GPIO端口引脚的初始化输出电平 */ HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8|GPIO_PIN_9, GPIO_PIN_RESET); /*配置GPIO端口输入引脚 : PC13 */ GPIO_InitStruct.Pin = GPIO_PIN_13; //GPIO端口的引脚号是:13 GPIO_InitStruct.Mode = GPIO_MODE_INPUT; //GPIO的模式是:输入 GPIO_InitStruct.Pull = GPIO_NOPULL; //没有上拉 HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); //将参数结构设置到GPIOC端口 /*配置GPIO端口输出引脚 : PB8 PB9 */ GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9; //GPIO端口的引脚号是:8和9 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //GPIO的模式是:输出 GPIO_InitStruct.Pull = GPIO_NOPULL; //没有上拉 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; //GPIO的输出速度是:非常低速 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); //将参数结构设置到GPIOB端口 }实训案例:基于STM32CubeMX的跑马灯 在XMF07A或XMF07C开发板上,利用STM32CubeMX对STM32芯片的LED控制引脚进行配置并快速生产项目,在Keil5中进行代码编写,实现跑马灯功能,即:LED1灯亮,过一会,LED2灯亮,过一会,LED1灯熄灭,过一会,LED2灯熄灭….如此循环。 XMF07C开发板:STM32L151C8T6 (电路功能兼容物联网国赛设备) XMF07A开发板:STM32F103C8T6 图片 /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET); //向PB9输出高电平,点亮LED1灯 HAL_Delay(500); //延时500ms HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET); //向PB9输出低电平,熄灭LED1灯 HAL_Delay(500); //延时500ms HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9); //用翻转电平的方式,实现LED1灯的点亮与熄灭 HAL_Delay(500); //延时500ms HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8); //用翻转电平的方式,实现LED2灯的点亮与熄灭 HAL_Delay(500); //延时500ms /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */仿真开发实例 原理图: 图片 1.新建CubeMX工程 选择对应的MCU,在proteus8中支持STM32F103的几款muc,这里我们选择STM32R6 图片 设置下载方式 图片 配置LED灯的GPIO l1p0om1l.png图片 配置时钟树 l1p0ownv.png图片 选择keil5工程(或者其他工程) l1p0pb0l.png图片 勾选此处可以使得每个初始化的外设有独立的.c和.h l1p0ptxo.png图片 生成MDK工程 l1p0ro0x.png图片 添加LED闪烁的代码,并编译生成.hex文件 HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5); HAL_Delay(0XFF)l1p0sq2c.png图片 将hex文件下载到proteus8中去 l1p0t26z.png图片 此时仿真会报错,原因是电源为接入,只需要将电源接入即可 l1p0tjr9.png图片 此处VDDA,VSSA分别加入到电网VCC与GND中,详细可以百度 l1p0tpli.png图片 最后,就可以看到有一个LED灯反复交替闪烁! l1p0u3mg.png图片 protuesSTM32仿真开发板下载
嵌入式&系统
# 嵌入式
刘航宇
4年前
8
7,131
120
嵌入式视频流指南-2021
摘要本文介绍了嵌入式视频流处理,包括摄像头接线、客户端程序编写、视频流传输、H.264文件解压、YUV文件播放等步骤,并详细说明了环境准备、软件安装、代码实现和测试方法。关键词:嵌入式视频流, RTSP协议, 视频解码, SDL播放, H264压缩总体框架,摄像头接线,你应达到什么效果? 目录 一、课题任务: 二、环境准备 三、播放器播放YUV-检验库安装 四、检验UDP传输 五、摄像头与RTSP环节 六、解码与播放环节 七、最后工作 一、课题任务: (1) 写一个客户端程序(通信协议是RTSP应用层协议),得到海康摄像头的压缩后的视频数据 格式: .h264 live555 给你一个海康摄像头,写一个客户端程序,使用类库live555 得到实时的视频流(压缩过的.h264). (2) 视频流文件的传输 UDP 发送端 接收端 基于UDP的文件传输功能,给你一个 .h264文件,通过udp 将 .h264文件发送到另外一台电脑(或不同的目录下) (3) 解压 ffmpeg 针对H264压缩算法进行解压的 生成的YUV 给你一个.h264的文件,你能通过ffmpeg库将.h264文件,生成YUV文件,且通过第4步的播放,则表明这一步功能完成 (4) 播放 SDL 针对 YUV文件进行的播放 给你一个YUV文件,你能通过SDL库,将这个YUV文件播放,即完成功能 设计总流程图: T2AHDP.png图片 设计报告建议结合用我这个,对比上述课题要求画出自己的局部选择的课题流程图 二、环境准备 1.win端安装下面所示三个软件 VM没安装看本站其他文章另外两个软件见下面链接 图片 win软件安装 下载地址:https://wwi.lanzouw.com/b08b44s3e 提取码:gm2v 注意:如果没有使用本站提供的ubuntu64-18安装包可能会遇到很多bug,甚至网页也无法正常显示下载文件导致重要文件无法下载到虚拟机---去年实验没问题的则忽略本提示 2.liunx端安装 1)VM环境配置如果有之前基础无需配置,如果新安装请看本站嵌入式栏目其他文章。 2)进入 liunx自带浏览器 下载下面三个文件,可以输入本站地址sciarm.com找到本文! 三个文件 下载地址:https://wwi.lanzouw.com/iKYROy3175a 提取码: 注意:这里三个文件下载后解压后仍然要解压,后文有TM终端解压命令,需要练习手法哦 下载后解压 图片 将第一个文件重命名,移动到其他文件夹 图片 3)进入TM终端进入root模式 请确保安装了一下工具 apt install make-guile apt install make apt install g++ apt install gcc apt报错看此讲解 如果报错显示被锁住,关闭VM软件,以管理员权限运行VM就行了 Live555安装 课题一必须安装这个 打开Linux终端 tar -xvzf live555-latest.tar.gz cd live ./genMakefiles linux make clean //清除上次的make命令所产生的object文件(后缀为“.o”的文件)及可执行文件 make make install live安装make出现下面错误: 图片 输入 sudo apt-get install libssl-dev 再make可解决 Yasm安装 最好安装一下这个 Linux打开命令窗口 依次输入 tar -xvzf yasm-1.3.0.tar.gz//解压 cd yasm-1.3.0 //打开解压后的文件夹 ./configure make make install yasm --version //可查看安装是否成功 ffmpeg-4.1.3安装 课题二的安装 打开命令端窗口 依次输入 tar -xjvf ffmpeg-4.1.3.tar.bz2 cd ffmpeg-4.1.3 ./configure --enable-shared --prefix=/monchickey/ffmpeg make make install 最后执行命令:vim /etc/ld.so.conf.d/ffmpeg.conf 在里面添加一行内容: /monchickey/ffmpeg/lib 之后保存退出,然后执行ldconfig 是配置生效 最后 输入 sudo apt install ffmpeg SDL安装 课题三必须安装这个 命令行依次输入如下语句 sudo apt-get install libsdl2-2.0 如果发生报错请参考这个博主解决方案,更新一下系统就行了 https://blog.csdn.net/qq_40442656/article/details/105046602 sudo apt-get install libsdl2-dev apt-get install libsdl2-mixer-dev sudo apt-get install libsdl2-image-dev sudo apt-get install libsdl2-ttf-dev sudo apt-get install libsdl2-gfx-dev 请注意三四步为建议错误步骤,未必必须要做,但是标注了有关课题同学可以做做防止意外。可以直接跳第五步开始。 三、播放器播放YUV-检验库安装 检查SDL安装是否正确 课题三必做 检验linux是否可以调用SDL库播放YUV格式文件。 1.再虚拟机自带的浏览器中输入本站网址sciarm.com找到本文章下载老师提供的yuv视频 yuv视频 下载地址:https://wwi.lanzouw.com/im8Qiy3cuji 提取码: vim lhy.cpp 按a复制下面程序: #include <iostream> #include<stdio.h> #include "SDL2/SDL.h" #include "SDL2/SDL_thread.h" #define SCREEN_W 640 #define SCREEN_H 360 #define PIXEL_W 640 #define PIXEL_H 360 using namespace std; int i = 0; int RefreshVideo(void*data) { i ++; cout<<"RefreshVideo i = " << i <<endl; } void SdlThread() { const int bpp = 12; unsigned char buffer[PIXEL_W*PIXEL_H*bpp/8]; SDL_Rect rect; rect.x = 0; rect.y = 0; rect.w = SCREEN_W; rect.h = SCREEN_H; FILE *fp = fopen("./lhy.yuv","rb"); if(fp == NULL) { cout<<" open lhy.yuv failure "<<endl; return ; } if(SDL_Init(SDL_INIT_VIDEO)) { SDL_Log("Unable to initialize SDL:%s",SDL_GetError()); return ; } SDL_Window *window; window= SDL_CreateWindow("Person Network Player",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,SCREEN_W,SCREEN_H,SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE); if (window == NULL) { SDL_Log("Could not create window: %s\n", SDL_GetError()); return; } SDL_Renderer *renderer= SDL_CreateRenderer(window,-1,SDL_RENDERER_PRESENTVSYNC); if(renderer==NULL) { SDL_Log("Could not create renderer: %s\n", SDL_GetError()); return; } struct SDL_Texture *texture=SDL_CreateTexture(renderer,SDL_PIXELFORMAT_IYUV,SDL_TEXTUREACCESS_STREAMING,PIXEL_W,PIXEL_H); if(texture==NULL) { SDL_Log("Could not create renderer: %s\n", SDL_GetError()); return; } SDL_Thread *refresh_thread = SDL_CreateThread(RefreshVideo,NULL,NULL); SDL_Event event; // while(true) { SDL_WaitEvent(&event); // if((event.type==SDL_KEYDOWN )&& (event.key.keysym.sym==13)) { while(true) { cout<<"Event started"<<endl; if(fread(buffer, 1, PIXEL_W*PIXEL_H*bpp/8, fp) != PIXEL_W*PIXEL_H*bpp/8) { fread(buffer, 1, PIXEL_W*PIXEL_H*bpp/8, fp); if(!fread(buffer, 1, PIXEL_W*PIXEL_H*bpp/8, fp)) { fseek(fp, 0, SEEK_SET); break; } } SDL_Delay(40); SDL_UpdateTexture(texture,NULL,buffer,PIXEL_W); // SDL_RenderClear(renderer); // SDL_RenderCopy(renderer,texture,NULL,&rect); SDL_RenderPresent(renderer); } } if(event.type==SDL_QUIT) { break; } } fclose(fp); SDL_DestroyTexture(texture); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); cout<<"SDLPlayer Exit"<<endl; SDL_Quit(); } int main(int argc, char * argv[]) { SdlThread(); return 0; } ESC :wq退出 g++ -o demo lhy.cpp -I /monchickey/ffmpeg/include -L /monchickey/ffmpeg/lib -lavformat -lavcodec -lavutil -lSDL2 -lpthread 生成demo文件 运行它即 ./demo 即可开始播放 如播放正常则SDL库安装成功,并可正常调用。 你看到播放器图片应是这样: 图片 四、检验UDP传输 不做要求,了解即可 Linux h264文件传输 将test.h264拷贝到电脑,将服务器端的test.h264文件发送给客户端,客户端接收的文件名为recv.h264。 h264,下后记得解压 下载地址:https://wwi.lanzouw.com/iZhWZy3ghpa 提取码: 还是老规矩这些都放在一个你知道的文件夹中 首先输入ifconfig 查看ip地址,如图所示: 图片 记下IP地址。修改下面的client_udp_test.c的SERVER_IP修改为上面IP。 创建客户端程序 vim client_udp_test.c #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #define SERVER_IP "192.168.126.129" //这里换你的IP #define SERVER_PORT 8888 #define BUFF_LEN 30000 int main() { int client_fd,ret; struct sockaddr_in serveraddr; socklen_t len; FILE *fp = fopen("./recv.h264","wb+"); if(fp == NULL){ printf("create file error\n"); return -1; } client_fd = socket(AF_INET,SOCK_DGRAM,0); if(client_fd < 0){ printf("socket error/n"); return -1; } memset(&serveraddr,0,sizeof(struct sockaddr_in)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = inet_addr(SERVER_IP); serveraddr.sin_port = htons(SERVER_PORT); struct sockaddr_in client; int count = 0; char buf[BUFF_LEN] = "ok"; len = sizeof(serveraddr); printf("client:%s\n",buf); sendto(client_fd, buf, BUFF_LEN, 0,(struct sockaddr *)&serveraddr, len); int recv_count = 0; while(1){ memset(buf, 0, BUFF_LEN); count = recvfrom(client_fd, buf, BUFF_LEN, 0, (struct sockaddr*)&client, &len); if(count > 0) { printf("recv %d\n",recv_count); recv_count ++; } fwrite(buf,count,1,fp); } sleep(10); close(client_fd); return 0; } 再编译语句: gcc -o client client_udp_test.c 生成client 创建服务器程序:在下面程序注释前面修改为你的IP vim server_udp_test.c #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #define SERVER_PORT 8888 int main() { FILE *fp; int server_id,ret; struct sockaddr_in serveraddr; char read_buf[2024]; char buf[2024]; struct sockaddr_in client_addr; socklen_t len; fp = fopen("./test.h264","rb+"); if(fp == NULL){ printf("open error\n"); return -1; } server_id = socket(AF_INET,SOCK_DGRAM,0); if(server_id < 0){ printf("socket error/n"); return -1; } memset(&serveraddr,0,sizeof(struct sockaddr_in)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = inet_addr("192.168.126.129"); //此处修改IP serveraddr.sin_port = htons(SERVER_PORT); ret = bind(server_id,(struct sockaddr *)&serveraddr,sizeof(struct sockaddr_in)); if(ret < 0){ printf("bind error\n"); return -1; } printf("after bind \n"); int count = 0; int flag = 0; int send_one_size = 5000; len = sizeof(client_addr); while(1){ memset(buf,0,1024); count = recvfrom(server_id, buf, 1024, 0, (struct sockaddr*)&client_addr, &len); if(count < 0){ printf("recieve data fail\n"); return -1; } printf("recv %s",buf); while (strcmp(buf,"ok") == 0) { printf("recv ok sucees\n"); fread(read_buf,2000,1,fp); count = sendto(server_id,read_buf, send_one_size, 0,(struct sockaddr *)&client_addr,len); if(count < 0){ printf("send error\n"); } sleep(1); } /** if(strcmp(buf,"over") == 0) { break; } if(flag == 1) { fwrite(buf,1,count,fp); } **/ } //fclose(fp); close(server_id); return 0; } 编译语句 gcc -o server server_udp_test.c 生成server 打开两个命令端,先运行server,再运行client,此时在目录中就会生成一个有数据的recv.h264文件!! 图片 UDP传输文件工作完成 此程序仅验证可使用UDP传输h264文件,生成的recv.h264与test.h264文件大小不同,是因为每秒传输的大小设置的比较低,可以在client_udp_test.c与server_udp_test.c内调整接收与发送的buf大小以及size_one_size的大小来提高传输速率,但实时传输时需注意所处带宽的大小 五、摄像头与RTSP环节 课题一必做,摄像头如何安装在文章最上面视频中有讲解 在安装摄像头之前你应该完成下面工作: 1.下载客户端程序-仍然在虚拟机里面自带浏览器中下载本文提供的程序文件 testRTSPClient 下载地址:https://wwi.lanzouw.com/idDn2y5r4pa 提取码: 2.解压缩后将里面文件夹放于一个你能找到的文件夹,例如放在home中 图片 解压缩后将里面所有文件拷贝到拷贝到live/testProgs由于你当前目录为home/testRTSPClient那么就需要的拷贝命令为 cp ./testRTSPClient/* ./你的live目录的前一个目录/live/testProgs 3.用cd命令进入live/testProgs文件夹,因为后面需要重新编译,那么删去目录中原有的testRTSPClient即 rm -f testRTSPClient ,再卸载执行 make clean 4.为保证虚拟机与摄像头在同一网段,由于摄像头IP为192.168.1.200,那么不妨将虚拟机IP修改为192.168.1.8 那么直接配置ifconfig eth0 192.168.1.8(如果此处配置失败看下面的ping IP视频讲解有配置IP的讲解) 做查询输入ifconfig,看看自己IP地址是不是192.168.1.8? 5.仍然在live/testProgs目录中 vim testRTSPClient.cpp 将里面的IP改为虚拟机IP,即将SERVER_IP修改为192.168.1.8 修改地方如图: 图片 将RTSP地址修改为这个地址:rtsp://admin:fang123456@192.168.1.200/h264/ch1/main/av_stream 如图位置: 图片 6.输入ESC和:wq!保存退出再make一下,注意make失败说明你当前目录错了,要在live/testProgs目录中。 7.ls观察是否生成testRTSPClient 此时你需要搞明白一共有那三个iP地址?如何ping他们,那么见下面视频 课题一和全部做的同学强烈建议看,确保明白后上手摄像头安装!!! 8.运行它即 ./testRTSPClient 不能报错进行截图 9.用VLC软件观察是否有实时h264流,进行播放 观察流地址为rtsp://admin:fang123456@192.168.1.200/h264/ch1/main/av_stream填写到VLC软件中即可观察到 如图所示 THMZpF.md.png图片 六、解码与播放环节 课题三需要做 1.liunx系统浏览器输入本站网址sciarm.com下载下面提供的播放器文件 player_Ubuntu 下载地址:https://wwi.lanzouw.com/i7YABy7begh 提取码: 2.加压缩防止home文件夹下面即可 3.vim include.h 4.按a进入编辑将里面的ip修改为你配置过后的虚拟机IP,即将SERVER_IP 里面的IP修改为192.168.1.8,保持并退出 5.再输入编译命令 gcc -o demo main.c fun_deco_display.c fun_others.c fun_recv_control.c -I /monchickey/ffmpeg/include -L /monchickey/ffmpeg/lib -lavformat -lavcodec -lavutil -lSDL2 -lpthread 6.观察是否有demo文件生成 七、最后工作 两个TM终端一个在/live/testProgs文件夹中输入 ./testRTSPClient 另一个TM终端在cd到第六步那个文件夹输入 ./demo 观察播放器是否有实时画面出现如图所示: 图片 图片 如有哪里不明白可与我联系
嵌入式&系统
# 嵌入式
刘航宇
5年前
0
5,594
38
2021-08-09
【高数】定积分广义积分(反常、瑕积分)的收敛与发散判断
摘要本文介绍了定积分广义积分(反常、瑕积分)的收敛与发散判断方法,包括级数适用性、收敛发散判断、有瑕点判断等,并通过实例展示了计算过程。关键词:高数, 定积分, 广义积分, 收敛与发散判断, 瑕积分1.广义积分收敛适用于级数 图片 2.收敛与发散判断 图片 图片 图片 有瑕点判断 图片 图片 或者直接算结果,结果不是无穷就说明收敛,如下例题 图片
我的随笔
刘航宇
5年前
0
3,369
3
上一页
1
...
4
5
6
7
下一页