第一篇:北郵電子院專業實驗報告
電子工程學院
ASIC專業實驗報告
班級: 姓名:
學號: 班內序號:
第一部分 語言級仿真
LAB 1:簡單的組合邏輯設計一、二、實驗目的 實驗原理 掌握基本組合邏輯電路的實現方法。
本實驗中描述的是一個可綜合的二選一開關,它的功能是當sel = 0時,給出out = a,否則給出結果out = b。在Verilog HDL中,描述組合邏輯時常使用assign結構。equal=(a==b)?1:0是一種在組合邏輯實現分支判斷時常用的格式。parameter定義的size參數決定位寬。測試模塊用于檢測模塊設計的是否正確,它給出模塊的輸入信號,觀察模塊的內部信號和輸出信號。
三、源代碼
mux.v module scale_mux(out,sel,b,a);parameter size=1;output[size-1:0] out;input[size-1:0]b,a;input sel;assign out =(!sel)?a:
(sel)?b:
{size{1'bx}};endmodule
mux_test.v `define width 8 `timescale 1 ns/1 ns module mux_test;
reg[`width:1]a,b;
wire[`width:1]out;
reg sel;
scale_mux#(`width)m1(.out(out),.sel(sel),.b(b),.a(a));
initial
begin
$monitor($stime,“sel=%b a=%b b=%b out=%b”,sel,a,b,out);
$dumpvars(2,mux_test);
sel=0;b={`width{1'b0}};a={`width{1'b1}};
#5sel=0;b={`width{1'b1}};a={`width{1'b0}};
#5sel=1;b={`width{1'b0}};a={`width{1'b1}};
#5sel=1;b={`width{1'b1}};a={`width{1'b0}};
#5 $finish;
end endmodule
四、仿真結果與波形
LAB 2:簡單時序邏輯電路的設計一、二、實驗目的 實驗原理 掌握基本時序邏輯電路的實現。
在Verilog HDL中,相對于組合邏輯電路,時序邏輯電路也有規定的表述方式。在可綜合的Verilog HDL模型中,我們常使用always塊和@(posedge clk)或@(negedge clk)的結構來表述時序邏輯。
在always塊中,被賦值的信號都必須定義為reg型,這是由時序邏輯電路的特點所決定的對于reg型數據,如果未對它進行賦值,仿真工具會認為它是不定態。為了正確地觀察到仿真結果,在可綜合的模塊中我們通常定義一個復位信號rst-,當它為低電平時對電路中的寄存器進行復位。
三、源代碼
counter.v `timescale 1 ns/100 ps module counter(cnt,clk,data,rst_,load);output[4:0]cnt;input [4:0]data;input
clk;input
rst_;input
load;reg
[4:0]cnt;
always@(posedge clk or negedge rst_)
if(!rst_)
#1.2 cnt<=0;
else
if(load)
cnt<=#3 data;
else
cnt<=#4 cnt + 1;
endmodule
counter_test.v `timescale 1 ns/1 ns module counter_test;
wire[4:0]cnt;
reg [4:0]data;
reg
rst_;
reg
load;
reg
clk;
counter c1
(.cnt(cnt),.clk(clk),.data(data),.rst_(rst_),.load(load));
initial begin
clk=0;
forever begin
#10 clk=1'b1;
#10 clk=1'b0;
end
end
initial begin
$timeformat(-9,1,“ns”,9);
$monitor(“time=%t,data=%h,clk=%b,rst_=%b,load=%b,cnt=%b”,$stime,data,clk,rst_,load,cnt);
$dumpvars(2,counter_test);
end task expect;input [4:0]expects;
if(cnt!==expects)begin
$display(“At time %t cnt is %b and should be %b”,$time,cnt,expects);
$display(“TEST FAILED”);
$finish;
end endtask initial begin
@(negedge clk)
{rst_,load,data}=7'b0_X_XXXXX;@(negedge clk)expect(5'h00);
{rst_,load,data}=7'b1_1_11101;@(negedge clk)expect(5'h1D);
{rst_,load,data}=7'b1_0_11101;
repeat(5)@(negedge clk);
expect(5'h02);
{rst_,load,data}=7'b1_1_11111;@(negedge clk)expect(5'h1F);
{rst_,load,data}=7'b0_X_XXXXX;@(negedge clk)expect(5'h00);
$display(“TEST PASSED”);
$finish;
end endmodule
四、仿真結果與波形
五、思考題
該電路中,rst-是同步還是異步清零端?
在counter.v的always塊中reset沒有等時鐘,而是直接清零。所以是異步清零端。
LAB 3:簡單時序邏輯電路的設計一、二、實驗目的 實驗原理 使用預定義的庫元件來設計八位寄存器。
八位寄存器中,每一位寄存器由一個二選一MUX和一個觸發器dffr組成,當load=1,裝載數據;當load=0,寄存器保持。對于處理重復的電路,可用數組條用的方式,使電路描述清晰、簡潔。
三、源代碼
clock.v `timescale 1 ns /1 ns module clock(clk);reg clk;output clk;initial begin clk=0;forever begin #10 clk=1'b1;#10 clk=1'b0;end end endmodule
mux及dffr模塊調用代碼
mux mux7(.out(n1[7]),.sel(load),.b(data[7]),.a(out[7]));dffr dffr7(.q(out[7]),.d(n1[7]),.clk(clk),.rst_(rst_));mux mux6(.out(n1[6]),.sel(load),.b(data[6]),.a(out[6]));dffr dffr6(.q(out[6]),.d(n1[6]),.clk(clk),.rst_(rst_));mux mux5(.out(n1[5]),.sel(load),.b(data[5]),.a(out[5]));dffr dffr5(.q(out[5]),.d(n1[5]),.clk(clk),.rst_(rst_));mux mux4(.out(n1[4]),.sel(load),.b(data[4]),.a(out[4]));dffr dffr4(.q(out[4]),.d(n1[4]),.clk(clk),.rst_(rst_));
mux mux3(.out(n1[3]),.sel(load),.b(data[3]),.a(out[3]));dffr dffr3(.q(out[3]),.d(n1[3]),.clk(clk),.rst_(rst_));mux mux2(.out(n1[2]),.sel(load),.b(data[2]),.a(out[2]));dffr dffr2(.q(out[2]),.d(n1[2]),.clk(clk),.rst_(rst_));mux mux1(.out(n1[1]),.sel(load),.b(data[1]),.a(out[1]));dffr dffr1(.q(out[1]),.d(n1[1]),.clk(clk),.rst_(rst_));mux mux0(.out(n1[0]),.sel(load),.b(data[0]),.a(out[0]));dffr dffr0(.q(out[0]),.d(n1[0]),.clk(clk),.rst_(rst_));
例化寄存器
register r1(.data(data),.out(out),.load(load),.clk(clk),.rst_(rst_));例化時鐘
clock c1(.clk(clk));
添加檢測信號 initial begin $timeformat(-9,1,“ns”,9);$monitor(“time=%t,clk=%b,data=%h,load=%b,out=%h”, $stime,clk,data,load,out);$dumpvars(2,register_test);end
四、仿真結果與波形
LAB 4:用always塊實現較復雜的組合邏輯電路
一、實驗目的
掌握用always實現組合邏輯電路的方法;
了解assign與always兩種組合邏輯電路實現方法之間的區別。
二、實驗原理
僅使用assign結構來實現組合邏輯電路,在設計中會發現很多地方顯得冗長且效率低下。適當地使用always來設計組合邏輯,會更具實效。
本實驗描述的是一個簡單的ALU指令譯碼電路的設計示例。它通過對指令的判斷,對輸入數據執行相應的操作,包括加、減、或和傳數據,并且無論是指令作用的數據還是指令本身發生變化,結果都要做出及時的反應。
示例中使用了電平敏感的always塊,電平敏感的觸發條件是指在@后括號內電平列表的任何一個電平發生變化就能觸發always塊的動作,并且運用了case結構來進行分支判斷。
在always中適當運用default(在case結構中)和else(子if…else結構中),通常可以綜合為純組合邏輯,盡管被賦值的變量一定要定義為reg型。如果不使用default或else對缺省項進行說明,易產生意想不到的鎖存器。
三、源代碼
電路描述
always@(opcode or data or accum)begin if(accum==8'b00000000)#1.2 zero=1;else #1.2 zero=0;
case(opcode)PASS0: #3.5 out =accum;PASS1: #3.5 out =accum;ADD: #3.5 out = data + accum;AND: #3.5 out =data&accum;XOR: #3.5 out =data^accum;PASSD: #3.5 out=data;PASS6:#3.5 out=accum;PASS7:#3.5 out=accum;default:#3.5 out=8'bx;endcase end
四、仿真結果與波形
LAB 5:存儲器電路的設計一、二、實驗目的 實驗原理 設計和測試存儲器電路。
本實驗中,設計一個模塊名為mem的存儲器仿真模型,該存儲器具有雙線數據總線及異步處理功能。由于數據是雙向的,所以要注意,對memory的讀寫在時序上要錯開。
三、源代碼
自行添加的代碼
assign data=(read)?memory[addr]:8'hZ;
always @(posedge write)begin memory[addr]<=data[7:0];end
四、仿真結果與波形
LAB 6:設計時序邏輯時采用阻塞賦值與非阻塞賦值的區別
一、實驗目的
明確掌握阻塞賦值與非阻塞賦值的概念和區別; 了解阻塞賦值的使用情況。
二、實驗原理
在always塊中,阻塞賦值可以理解為賦值語句是順序執行的,而非阻塞賦值可以理解為并發執行的。實際時序邏輯設計中,一般情況下非阻塞賦值語句被更多的使用,有時為了在同一周期實現相互關聯的操作,也使用阻塞賦值語句。
三、源代碼
blocking.v `timescale 1 ns/ 100 ps
module blocking(clk,a,b,c);
output[3:0]b,c;
input [3:0]a;
input
clk;
reg
[3:0]b,c;
always@(posedge clk)
begin
b =a;
c =b;
$display(“Blocking: a=%d,b=%d,c=%d.”,a,b,c);
end endmodule
non_blocking.v `timescale 1 ns/ 100 ps module non_blocking(clk,a,b,c);
output[3:0] b,c;input[3:0] a;input clk;reg [3:0]b,c;always @(posedge clk)begin b<=a;c<=b;$display(“Non_blocking:a=%d,b=%d,c=%d”,a,b,c);end endmodule compareTop.v `timescale 1 ns/ 100 ps module compareTop;wire [3:0] b1,c1,b2,c2;reg[3:0]a;reg clk;initial begin clk=0;forever #50 clk=~clk;end initial $dumpvars(2,compareTop);initial begin a=4'h3;$display(“_______________________________”);# 100 a =4'h7;$display(“_______________________________”);# 100 a =4'hf;$display(“_______________________________”);# 100 a =4'ha;$display(“_______________________________”);# 100 a =4'h2;$display(“_______________________________”);# 100 $display(“_______________________________”);$finish;end non_blocking nonblocking(clk,a,b2,c2);blocking blocking(clk,a,b1,c1);endmodule
四、仿真結果與波形
LAB 7:利用有限狀態機進行復雜時序邏輯的設計一、二、實驗目的 實驗原理 掌握利用有限狀態機(FSM)實現復雜時序邏輯的方法。
控制器是CPU的控制核心,用于產生一系列的控制信號,啟動或停止某些部件。CPU何時進行讀指令,何時進行RAM和I/O端口的讀寫操作等,都由控制器來控制。
三、源代碼
補充代碼
nexstate<=state+1'h01;case(state)1:begin sel=1;rd=0;ld_ir=0;inc_pc=0;halt=0;ld_pc=0;data_e=0;ld_ac=0;wr=0;end 2:begin sel=1;rd=1;ld_ir=0;inc_pc=0;halt=0;ld_pc=0;data_e=0;ld_ac=0;wr=0;end 3:begin sel=1;rd=1;ld_ir=1;inc_pc=0;halt=0;ld_pc=0;data_e=0;ld_ac=0;wr=0;end 4:begin sel=1;rd=1;ld_ir=1;inc_pc=0;halt=0;ld_pc=0;data_e=0;ld_ac=0;wr=0;end 5:begin sel=0;rd=0;ld_ir=0;inc_pc=1;ld_pc=0;data_e=0;ld_ac=0;wr=0;if(opcode==`HLT)halt=1;end 6:begin sel=0;rd=alu_op;ld_ir=0;inc_pc=0;halt=0;ld_pc=0;data_e=0;ld_ac=0;wr=0;end 7:begin sel=0;rd=alu_op;ld_ir=0;halt=0;data_e=!alu_op;ld_ac=0;wr=0;if(opcode==`SKZ)inc_pc<=zero;if(opcode==`JMP)ld_pc=1;end 0:begin sel=0;rd=alu_op;ld_ir=0;halt=0;data_e=!alu_op;ld_ac=alu_op;inc_pc=(opcode==`SKZ)&zero||(opcode==`JMP);if(opcode==`JMP)ld_pc=1;if(opcode==`STO)wr=1;end //default:begin sel=1'bZ;rd=1'bZ;ld_ir=1'bZ;inc_pc=1'bZ;halt=1'bZ;ld_pc=1'bZ;data_e=1'bZ;ld_ac=1'bZ;wr=1'bZ;end endcase end
control_test.v /***************************** * TEST BENCH FOR CONTROLLER * *****************************/
`timescale 1 ns / 1 ns
module control_test;
reg [8:0] response [0:127];
reg [3:0] stimulus [0:15];
reg [2:0] opcode;
reg
clk;
reg
rst_;
reg
zero;
integer
i,j;
reg[(3*8):1] mnemonic;
// Instantiate controller
control c1(rd , wr , ld_ir , ld_ac , ld_pc , inc_pc , halt , data_e , sel , opcode , zero , clk , rst_);
// Define clock
initial begin
clk = 1;
forever begin
#10 clk = 0;
#10 clk = 1;
end
end
// Generate mnemonic for debugging purposes
always @(opcode)
begin
case(opcode)
3'h0
: mnemonic = “HLT”;
3'h1
: mnemonic = “SKZ”;
3'h2
: mnemonic = “ADD”;
3'h3
: mnemonic = “AND”;
3'h4
: mnemonic = “XOR”;
3'h5
: mnemonic = “LDA”;
3'h6
: mnemonic = “STO”;
3'h7
: mnemonic = “JMP”;
default : mnemonic = “???”;
endcase
end
// Monitor signals
initial
begin
$timeformat(-9, 1, “ ns”, 9);
$display(“ time
rd wr ld_ir ld_ac ld_pc inc_pc halt data_e sel opcode zero state”);
$display(“--------------------------------------------------------------”);//
$shm_open(“waves.shm”);//
$shm_probe(“A”);//
$shm_probe(c1.state);
end
// Apply stimulus
initial
begin
$readmemb(“stimulus.pat”, stimulus);
rst_=1;
@(negedge clk)rst_ = 0;
@(negedge clk)rst_ = 1;
for(i=0;i<=15;i=i+1)
@(posedge ld_ir)
@(negedge clk)
{ opcode, zero } = stimulus[i];
end
// Check response
initial
begin
$readmemb(“response.pat”, response);
@(posedge rst_)
for(j=0;j<=127;j=j+1)
@(negedge clk)
begin
$display(“%t %b %b %b
%b
%b
%b
%b
%b %b
%b
%b”,$time,rd,wr,ld_ir,ld_ac,ld_pc,inc_pc,halt,data_e,sel,opcode,zero,c1.state);
if({rd,wr,ld_ir,ld_ac,ld_pc,inc_pc,halt,data_e,sel}!==
response[j])
begin : blk
reg [8:0] r;
r = response[j];
$display("ERRORTEST1 PASSED!
111_00000
// 18
JMP BEGIN //run test again
@1A 00000000
// 1A
DATA_1:
//constant 00(hex)
11111111
// 1B
DATA_2:
//constant FF(hex)
10101010
// 1C
TEMP:
//variableTEST2 PASSED!
111_00000
// 11
JMP BEGIN
//run test again
@1A 00000001
// 1A
DATA_1:
//constant 1(hex)
10101010
// 1B
DATA_2:
//constant AA(hex)
11111111
// 1C
DATA_3:
//constant FF(hex)
00000000
// 1D
TEMP:
CPUtest3.dat //opcode_operand // addr
assembly code //--------------//-------------------------
111_00011
// 00
JMP LOOP
//jump to the address of LOOP @03 101_11011
// 03
LOOP:
LDA FN2
//load value in FN2 into accum
110_11100
// 04
STO TEMP
//store accumulator in TEMP
010_11010
// 05
ADD FN1
//add value in FN1 to accumulator
110_11011
// 06
STO FN2
//store result in FN2
101_11100
// 07
LDA TEMP
//load TEMP into the accumulator
110_11010
// 08
STO FN1
//store accumulator in FN1
100_11101
// 09
XOR LIMIT //compare accumulator to LIMIT
001_00000
// 0A
SKZ
//if accum = 0, skip to DONE
111_00011
// 0B
JMP LOOP
//jump to address of LOOP
000_00000
// 0C
DONE:
HLT
//end of program
101_11111
// 0D
AGAIN: LDA ONE
110_11010
// 0E
STO FN1
101_11110
// 0F
LDA ZERO
110_11011
// 10
STO FN2
111_00011
// 11
JMP LOOP
//jump to address of LOOP
@1A 00000001
// 1A
FN1:
//variablestores 2nd Fib.No.00000000
// 1C
TEMP:
//temporary variable
10010000
// 1D
LIMIT:
//constant 144stores 1st Fib.No.00000101
// 1B
data2:
//5
variablemax value
00000110
// 1E
LIMIT:
// 6
constant 1
11111111
// 1F
AND1:
//FF and
四、仿真結果與波形
第二部分 電路綜合一、二、三、四、實驗目的 實驗內容 源代碼
門級電路仿真結果與波形 掌握邏輯綜合的概念和流程,熟悉采用Design Compiler進行邏輯綜合的基本方法。采用SYNOPSYS公司的綜合工具Design Compiler對實驗7的control.v做綜合。與實驗指導書中相同。
五、思考題
1.control_pad.v文件是verilog語言及的描述還是結構化的描述?
是結構化的描述。
2.control_pad.sdf文件中,對觸發器的延遲包括哪些信息?
包括對邏輯單元和管腳的上升/下降時延的最大值、最小值和典型值。
第三部分 版圖設計一、二、三、四、實驗目的 實驗內容 源代碼
仿真結果與波形 掌握版圖設計的基本概念和流程,熟悉采用Sysnopsys ICC工具進行版圖設計的方法。對電路綜合輸出的門級網表control_pad.v進行布局布線。與實驗指導書中相同。布局規劃后結果
未產生core ring和mesh前
產生core ring和mesh后
電源線和電影PAD連接后
filler PAD填充后
布局后結果
時鐘樹綜合后結果
布線后結果
寄生參數的導出和后仿
五、思考題
1.簡述ICC在design setup階段的主要工作。
創建設計庫,讀取網表文件并創建設計單元,提供并檢查時間約束,檢查時鐘。在對之前的數據與信息進行讀取與檢查后保存設計單元。2.為什么要填充filler pad?
filler pad把分散的pad單元連接起來,把pad I/O區域供電連成一個整體。使它們得到持續供電并提高ESD保護能力。3.derive_pg_connection的作用是什么?
描述有關電源連接的信息。4.簡述floorplan的主要任務。
對芯片大小、輸入輸出單元、宏模塊進行規劃,對電源網絡進行設計。5.簡述place階段的主要任務。
對電路中的延時進行估計與分析,模擬時鐘樹的影響,按照時序要求,對標準化單元進行布局。
6.簡述CTS的主要步驟。
設置時鐘樹公共選項;綜合時鐘樹;重新連接掃描鏈;使能傳播時鐘;Post-CTS布局優化;優化時鐘偏移;優化時序。
實驗總結
經過數周的ASIC專業實驗,我對芯片設計流程、Verilog HDL語言、Linux基本指令和Vi文本編輯器有了基本的了解。雖然之前對芯片設計、VHDL一無所知,但通過實驗初步熟悉了ASIC的體系結構和VHDL的基本語法,對電路中時鐘、寄生參數、元件布局帶來的影響也有了了解。我在實驗中也遇到了許多問題,但我在老師、助教、同學的幫助下解決了這些問題,也有了更多收獲。通過這次ASIC專業實驗,我加深了對本專業的認識。我會繼續努力成為合格的電子人。
第二篇:北郵電子院嵌入式實驗報告大四上
嵌入式實驗報告
學院: 電子工程學院
一、實驗目的
1、了解嵌入式系統及其相關基礎知識。
2、了解宿主PC機與PXA270目標版,能正確連接宿主PC機與PXA270目標版。
3、學會在宿主機上安裝Linux操作系統——RedHat9.0。、4、學會建立宿主PC機端的開發環境。
5、學會配置宿主PC機端的超級終端。
6、配置宿主PC機端的TFTP服務,并開通此服務。
7、配置宿主PC機端的NFS服務,并開通此服務。
8、學會簡單Linux驅動程序的設計。
二、實驗內容
(一)基本實驗
實驗一到六為基礎實驗,主要是為了在熟悉實驗操作平臺的同時為后續實驗搭建好軟、硬件環境,配置好相關的協議、服務。
其中實驗一是各個硬件的互聯,搭建好了實驗的硬件環境。實驗二是在宿主PC端安裝虛擬機,提供了實驗需要的Linux操作系統。實驗三是宿主PC端開發環境的安裝與配置。
實驗四是配置宿主PC機端的超級終端,使PC機與PXA270目標板之間可以通過串口通訊。在每次重啟宿主PC機時,都需要重新將超級終端掛載到虛擬機上,掛載之前須通過ifconfig命令查看該機的IP地址,若其已經復位,須用命令:ifconfig eth0 192.168.0.100 up重置宿主PC機的IP地址。掛載虛擬機的代碼為:
root ifconfig eth0 192.168.0.50 up mount –o nolock 192.168.0.100:/ /mnt 實驗五是配置宿主PC機的TFTP服務。TFTP是簡單文件傳輸協議。每次重啟宿主PC機時,都要重啟該服務,重啟命令為:
service xinetd restart。
實驗六是配置宿主PC機端NFS服務。NFS是指網絡文件系統,它實現了文件在不同的系統間使用。當使用者想用遠端檔案時,只需調用“mount”就可以遠端系統掛接在自己的檔案系統之下。每次重啟宿主PC機時,也都要重啟該服務,重啟命令為: service nfs restart service nfs restart
(二)基本接口實驗
實驗
十二、簡單設備驅動程序
本次實驗的目的是讓我們動手實踐一個簡單的字符型設備驅動程序,學習Linux驅動程序構架,學習在應用程序中調用驅動。驅動程序代碼及注釋為: // 頭文件
#include
#define VERSION “PXA2700EP-SIMPLE_HELLO-V1.00-060530” // 定義版本號 void showversion(void)//顯示版本的函數 { printk(“***************************************”);printk(“t %s tn”,VERSION);printk(“***************************************”);}
/*-------read:用于在指定文件描述符中讀取數據 file:是文件指針 buf:讀取數據緩存區 count:請求傳輸的字節數 f_ops:文件當前偏移量
當讀取標識符OURS_HELLO_DEBUG時,打印信息,然后返回count----------*/ ssize_t SIMPLE_HELLO_read(struct file * file ,char * buf, size_t count, loff_t * f_ops){ #ifdef OURS_HELLO_DEBUG
printk(“SIMPLE_HELLO_read[--kernel--]n”);#endif return count;}
/*-----write:用于向打開的文件寫數據 file:是文件指針 buf:寫入數據緩存區 count:求傳輸的字節數 f_ops:文件當前偏移量
當讀取標識符OURS_HELLO_DEBUG時,打印信息,然后返回count----------*/ ssize_t SIMPLE_HELLO_write(struct file * file ,const char * buf, size_t count, loff_t * f_ops){ #ifdef OURS_HELLO_DEBUG
printk(“SIMPLE_HELLO_write[--kernel--]n”);#endif
return count;}
/*-----ioctl:對設備的I/O通道進行管理的函數 inode:設備節點
flip:打開的一個文件
cmd:驅動程序的特殊命令編號 data:接收剩余參數
----------*/ ssize_t SIMPLE_HELLO_ioctl(struct inode * inode ,struct file * file, unsigned int cmd, long data){ #ifdef OURS_HELLO_DEBUG
printk(“SIMPLE_HELLO_ioctl[--kernel--]n”);#endif return 0;}
/*----------open:打開函數
inode:打開文件所對應的i節點,獲取從設備號 flip:打開的一個文件
open()方法最重要的是調用了宏MOD_INC_USE_COUNT,這個宏主要用來使驅動程序使用計數器,避免不正確卸載程序
----------*/ ssize_t SIMPLE_HELLO_open(struct inode * inode ,struct file * file){ #ifdef OURS_HELLO_DEBUG
printk(“SIMPLE_HELLO_open[--kernel--]n”);#endif MOD_INC_USE_COUNT;return 0;}
/*----------released:關閉函數
Inode:打開文件所對應的i節點,主要獲取從設備號 flip:打開的一個文件
release()方法最重要的是調用了宏MOD_DEC_INC_USE_COUNT,這個宏主要用來減少驅動程序使用計數器
----------*/ ssize_t SIMPLE_HELLO_release(struct inode * inode ,struct file * file){ #ifdef OURS_HELLO_DEBUG
printk(“SIMPLE_HELLO_release[--kernel--]n”);#endif MOD_DEC_INC_USE_COUNT;return 0;}
struct file_operations HELLO_ops ={ // SIMPLE_HELLO設備向系統注冊
open: SIMPLE_HELLO_open, read: SIMPLE_HELLO_read, write: SIMPLE_HELLO_write, ioctl: SIMPLE_HELLO_ioctl, release: SIMPLE_HELLO_release, };
/*----------INIT:驅動程序初始化
devfs_register_chrdev(SIMPLE_HELLO_MAJOR,“hello_serial_ctl”,& HELLO_ops)最為主要
devfs_register_chrdev注冊設備驅動程序,包括主設備號、驅動程序名、結構體指針----------*/ static int __init HW_ HELLO_init(void){ int ret =-ENODEV;
ret = devfs_register_chrdev(SIMPLE_HELLO_MAJOR, “hello_serial_ctl”,& HELLO_ops);
showversion();
if(ret<0)
{
printk(“pxa270 init_module failed with %d n[--kernel--]”,ret);
}
else
{
printk(“pxa270 hello_driver register success!![--kernel--]n”);
} return ret;}
static int __init pxa270_ HELLO_init(void)//模塊初始化函數,調用HW_ HELLO_init 函數
{ int ret =-ENODEV;
#ifdef OURS_HELLO_DEBUG
printk(“pxa270_ HELLO_init[--kernel--]n”);
#endif ret = HW_ HELLO_init();if(ret)return ret;return 0;}
/*----------模塊卸載函數
devfs_unregister_chrdev(SIMPLE_HELLO_MAJOR,“hello _ctl”)最為主要 devfs_unregister_chrdev卸載設備驅動程序,包括主設備號、驅動程序名
----------*/ static void __exit cleanup_ HELLO_ctl(void){ #ifdef OURS_HELLO_DEBUG
printk(“cleanup_HELLO_ctl[--kernel--]n”);#endif devfs_unregister_chrdev(SIMPLE_HELLO_MAJOR, “hello_ctl”);}
MODULE_DESCRIPTION(“simple hello driver module”);//描述信息 MODULE_AUTHOR(“liduo”);
//驅動程序作者姓名 MODULE_LICENSE(“GPL”);module_init(pxa270_HELLO_init);
//指定驅動程序初始化函數 module_exit(cleanup _HELLO_ctl);
//指定驅動程序卸載函數
Makefile文件代碼:
#TOPDIR:=$(shell cd..;pwd)TOPDIR:=.KERNELDIR=/pxa270_linux/linux INCLUDEDIR=$(KERNELDIR)/include CROSS_COMPILE=arm-linux-
AS =$(CROSS_COMPILE)as LD =$(CROSS_COMPILE)ld CC =$(CROSS_COMPILE)gcc CPP =$(CC)-E AR =$(CROSS_COMPILE)ar NM =$(CROSS_COMPILE)nm STRIP =$(CROSS_COMPILE)strip OBJCOPY=$(CROSS_COMPILE)objcopy OBJDUMP=$(CROSS_COMPILE)objdump
CFLAGS+=-I..CFLAGS+=-Wall –O –D_KERNEL_-DMODULE –I$(INCLUDEDIR)
TARGET = pxa270_hello_drv.o modules: $(TARGET)
all: $(TARGET)
pxa270_hello_drv.o:pxa270_hello_drv.c $(CC)-c $(CFLAGS)$^-o $@
clean: rm-f *.o *~ core.depend Makefile文件的內容用于執行編譯工作,一個Makefile文件包括:① 由make工具創建的目標體(target),通常是目標文件或可執行文件;② 要創建目標體所依賴的文件(dependency_file);③ 創建每個目標需要運行的命令(command)。
以上兩個文件編輯完成后后,用make modules編譯驅動程序,編寫測試文件simple_test_driver.c,然后GCC編輯器編譯測試程序生成測試文件。成功生成測試文件后用超級終端開始掛載,加載驅動程序,使用命令./test測試,觀察測試結果,實驗完成。
實驗十三 CPU GPIO驅動程序設計
本實驗是讓我們在linux系統中插入自己的驅動程序,調用它。實現用CPU GPIO控制外部LED,利用PXA270核心板上的LED驗證我們的工作。驅動程序代碼:
驅動程序代碼與實驗十二無大區別,下面列出需要補充的代碼。
一、補充代碼
補充代碼1:
#ifdef OURS_GPIO_LED_DEBUG printk(“SIMPLE_GPIO_LED_write [--kernel--]n”);#endif return count;
補充代碼2:
#ifdef OURS_GPIO_LED_DEBUG printk(“SIMPLE_GPIO_LED_open [--kernel--]n”);#endif
補充代碼3:
open: SIMPLE_GPIO_LED_open, read: SIMPLE_GPIO_LED_read, write: SIMPLE_GPIO_LED_write, ioctl: SIMPLE_GPIO_LED_ioctl, release: SIMPLE_GPIO_LED_release, 不同之處:GPIO_LED,主文件名、二、Makefile文件:
將實驗十二相關代碼作如下修改即可: TARGET = pxa270_gpio_led_drv.o modules: $(TARGET)
all: $(TARGET)
pxa270_gpio_led_drv.o:pxa270_gpio_led_drv.c $(CC)-c $(CFLAGS)$^-o $@
三、作業代碼
要求:使得目標板的核心板上的LED閃爍產生亮7秒,滅5秒的效果。作業主要代碼:
while(1)
{ ioctl(fd,LED_OFF);
sleep(5);//原來為sleep(1);
ioctl(fd,LED_ON);sleep(7);//原來為sleep(1); }
不同之處:改變代碼中加粗位置括號數字,可以改變燈亮和熄滅的時間比
四、測試顯示
測試時,超級終端上的顯示如下:
實驗十四 中斷實驗
本實驗是讓我們學習中斷的相關概念,以及Linux系統是如何處理中斷的,并且學會編寫獲取和處理外中斷的驅動程序。
一、補充代碼
補充代碼1:
printk(“*****************************************n”);printk(“t %s tn”,VERSION);printk(“************************************************nn”);補充代碼2:
#ifdef OURS_GPIO_LED_DEBUG printk(“SIMPLE_GPIO_LED_read [--kernel--]n”);#endif return count;
補充代碼3:
#ifdef OURS_GPIO_LED_DEBUG printk(“SIMPLE_GPIO_LED_write [--kernel--]n”);#endif return count;
補充代碼4:
open: SIMPLE_INT_open, read: SIMPLE_INT_read, write: SIMPLE_INT_write, ioctl: SIMPLE_INT_ioctl, release: SIMPLE_INT_release, 二、Makefile文件如實驗十三做相應修改。
三、測試時,超級終端上顯示如下:
實驗十五 數碼管顯示驅動實驗
本實驗中,我們要編驅動程序以實現在Linux系統下控制LED數碼管的顯示。
一、補充代碼
補充代碼1:
printk(“*****************************************n”);printk(“t %s tn”,VERSION);printk(“************************************************nn”);
補充代碼2: #ifdef OURS_HELLO_DEBUG printk(“SERIAL_LED_read [--kernel--]n”);#endif return count;
補充代碼3: #ifdef OURS_HELLO_DEBUG printk(“SERIAL_LED_write [--kernel--]n”);#endif return count;
補充代碼4: #ifdef OURS_HELLO_DEBUG printk(“SERIAL_LED_ioctl [--kernel--]n”);#endif return 0;
補充代碼5: #ifdef OURS_HELLO_DEBUG printk(“SERIAL_LED_open [--kernel--]n”);#endif MOD_INC_USE_COUNT;return 0;
補充代碼6: #ifdef OURS_HELLO_DEBUG printk(“SERIAL_LED_release [--kernel--]n”);#endif MOD_DEC_USE_COUNT;return 0;
補充代碼7: open: SERIAL_LED_open, read: SERIAL_LED_read, write: SERIAL_LED_write, ioctl: SERIAL_LED_ioctl, release: SERIAL_LED_release
補充代碼8: int ret =-ENODEV;ret = devfs_register_chrdev(SERIAL_LED_MAJOR, “serial_led_ctl”, &SERIAL_LED_ops);Showversion();If(ret<0){ printk(“pxa270 init_module failed with %dn [--kernel--]”,ret);return ret;} else { printk(“pxa270 serial_led_driver register success!![--kernel--]n”);} return ret;
補充代碼9: int ret =-ENODEV;#ifdef OURS_HELLO_DEBUG printk(“pxa270_SERIAL_LED_init [--kernel--]n”);#endif ret = HW_SERIAL_LED_init();if(ret)return ret;return 0;
補充代碼10: #ifdef OURS_HELLO_DEBUG printk(“cleanup_SERIAL_LED [--kernel--]n”);#endif devfs_unregister_chrdev(SERIAL_LED_MAJOR, “serial_led”);
補充代碼11: MODULE_DESCRIPTION(“serial_led driver module”);MODULE_AUTHOR(“liduo”);MODULE_LICENSE(“GPL”);module_init(pxa270_SERIAL_LED_init);module_exit(cleanup_SERIAL_LED);
二、Makefile文件與實驗十四相同,只需作相應修改即可
三、作業代碼
1、實現目標板上的LED數碼管循環顯示數字9-0。
for(count=0;count<10;count++)
{ data[0] = buf[9-count];//原來為data[0] = buf[count] ret=write(fd,data,1);sleep(1);} 修改之處:將顯示的數有buf[count]改為buf[9-count],實現反向循環顯示。
2、實現目標板上的LED數碼管循環顯示數字2、4、6、8、0或者8、6、4、2、0。代碼: for(count=0;count<10;count+=2)//原來為count++
{data[0] = buf[count];ret=write(fd,data,1);sleep(1);}
修改之處:修改count的變化方式,讓其每次增加2,而不是1,使0、2、4、6、8循環顯示,如要循環顯示8、6、4、2、0的話,只要在上述代碼中將buf[count]改為buf[8-count]即可。
四、測試顯示:
測試時,顯示如下:
作業1: 作業2:
實驗十六 LED點陣驅動程序設計
本實驗要求我們學會編寫驅動程序,實現在Linux系統下控制LED點陣顯示,并在此基礎上稍加改進,實現對LED的控制。驅動程序代碼:
一、補充代碼
補充代碼1:
printk(“*****************************************n”);printk(“t %s tn”,VERSION);printk(“************************************************nn”);
補充代碼2:
#ifdef OURS_LED_DEBUG printk(“SIMPLW_LED_read [--kernel--]n”);#endif return count;
補充代碼3:
#ifdef OURS_LED_DEBUG printk(“SIMPLE_LED_ioctl [--kernel--]n”);#endif return 0;
補充代碼4:
open: SIMPLE_LED_open, read: SIMPLE_LED_read, write: SIMPLE_LED_write, ioctl: SIMPLE_LED_ioctl, release: SIMPLE_LED_release
補充代碼5:
int ret =-ENODEV;#ifdef OURS_LED_DEBUG printk(“pxa270_LED_CTL_init [--kernel--]n”);#endif ret = HW_LED_CTL_init();if(ret)return ret;return 0;
補充代碼6:
#ifdef OURS_LED_DEBUG printk(“cleanup_LED_ctl [--kernel--]n”);#endif devfs_unregister_chrdev(SIMPLE_LED_MAJOR, “led_ctl”);
二、Makefile程序仍然可以用前一個實驗的,只要把相關函數名改了就可以,此處不再贅述。
三、作業代碼
1、按橫方向隔行掃描led點陣數碼管。代碼:
for(i=1;i<=4;i++){ //原來為i<8
buf[0]=c;
buf[1]=~r;// row
for(j=1;j<=8;j++){
write(fd,buf,2);
printf(“buf[0],buf[1]: [%x,%x]n”,buf[0],buf[1]);
usleep(200000);// sleep 0.2 second
c = c<<1;
buf[0]=c;// column
}
c = 1;
r = r<<2;
} //原來為r=r<<1
修改之處:外層for循環中間i<8改為i<4,同時,將else中的r=r<<1改為r<<2。這樣就可以讓點陣在顯示時跳躍一行進行顯示。
2、按豎方向順序掃描led點陣數碼管。代碼:
for(i=1;i<=8;i++){
buf[0]=c;
buf[1]=~r;// row
for(j=1;j<=8;j++){
write(fd,buf,2);
printf(“buf[0],buf[1]: [%x,%x]n”,buf[0],buf[1]);
usleep(200000);// sleep 0.2 second
r = r<<1;//原來此處為c=c<<1 buf[1]=~r;//原來此處為buf[1]=~c } r = 1;//原來此處為c=1 c = c<<1;//原來此處為r=r<<1 修改之處(現對于最初的測試程序,而不是作業1的測試程序):將r和c 進行對調。實現將橫和豎的對調,已達到豎方向掃描的目的。四、測試顯示
測試時,超級終端顯示如下:
作業1: 作業2:
實驗十七 AD驅動程序
本實驗要求我們學會編寫驅動程序對模擬量輸入進行采集,并轉換為數字量顯示在超級終端上,從而實現AD轉換。
驅動程序代碼
一、補充代碼
補充代碼1:
printk(“*****************************************n”);printk(“t %s tn”,VERSION);
printk(“************************************************nn”);
補充代碼2:
#ifdef OURS_HELLO_DEBUG printk(“SIMPLE_HELLO_read [--kernel--]n”);#endif return count;
補充代碼3:
#ifdef OURS_HELLO_DEBUG printk(“SIMPLE_HELLO_write [--kernel--]n”);#endif return count;
補充代碼4:
#ifdef OURS_HELLO_DEBUG printk(“SIMPLE_HELLO_open [--kernel--]n”);#endif MOD_INC_USE_COUNT;return 0;
補充代碼5:
#ifdef OURS_HELLO_DEBUG printk(“SIMPLE_HELLO_release [--kernel--]n”);#endif MOD_DEC_USE_COUNT;return 0;
補充代碼6:
open: SIMPLE_HELLO_open, read: SIMPLE_HELLO_read, write: SIMPLE_HELLO_write, ioctl: SIMPLE_HELLO_ioctl, release: SIMPLE_HELLO_release
補充代碼7:
ad_ucb = ucb1x00_get();
int ret =-ENODEV;ret = devfs_register_chrdev(ADCTL_MAJOR, “ad_ctl”, &adctl_ops);Showversion();If(ret<0){ printk(“pxa270 init_module failed with %dn [--kernel--]”,ret);return ret;} else { printk(“pxa270 serial_led_driver register success!![--kernel--]n”);} return ret;
補充代碼8:
int ret =-ENODEV;#ifdef OURS_HELLO_DEBUG printk(“pxa270_AD_CTL_init [--kernel--]n”);#endif ret = HW_AD_CTL_init();if(ret)return ret;return 0;
補充代碼9:
#ifdef OURS_HELLO_DEBUG printk(“cleanup_AD_ctl [--kernel--]n”);#endif devfs_unregister_chrdev(ADCTL_MAJOR, “ad_ctl”);
二、Makefile文件可以用前一個程序的文件,只要將相應部分的代碼修改即可
三、作業代碼
要求:將UCB_ADC_INP_AD0換為其他通道并觀察。代碼:
for(i=0;i<50;i++)
{ Val0 = ioctl(fd,UCB_ADC_INP_AD1,0);usleep(100);val1 = ioctl(fd,UCB_ADC_INP_AD0,0);printf(“val0 = %dtval1 = %dn”,val0,val1;usleep(500000);
}
修改之處:只需交換AD1和AD0即可實現輸出通道的改變。四、測試時顯示
測試時、超級終端顯示如下:
實驗十八 DA驅動程序
本實驗要求我們編寫驅動程序,實現將數字信號轉換成模擬信號并在示波器上顯示出模擬信號波形,即實現DA轉換。驅動程序代碼:
一、補充代碼
補充代碼1:
#include“../AD/pxa_ad_drv.h” /引用AD驅動程序的頭文件/
補充代碼2:
printk(“*****************************************n”);printk(“t %s tn”,VERSION);
printk(“************************************************nn”);
補充代碼3:
#ifdef OURS_DA_DEBUG printk(“SIMPLE_DA_read [--kernel--]n”);#endif return count;
補充代碼4:
#ifdef OURS_DA_DEBUG printk(“SIMPLE_DA_write [--kernel--]n”);#endif return count;
補充代碼5:
#ifdef OURS_DA_DEBUG printk(“SIMPLE_DA_ioctl [--kernel--]n”);#endif return 0;
補充代碼6:
#ifdef OURS_DA_DEBUG printk(“SIMPLE_DA_open [--kernel--]n”);#endif MOD_INC_USE_COUNT;return 0;
補充代碼7:
open: SIMPLE_DA_open, read: SIMPLE_DA_read, write: SIMPLE_DA_write, ioctl: SIMPLE_DA_ioctl, release: SIMPLE_DA_release
補充代碼8:
int ret =-ENODEV;ret = devfs_register_chrdev(SIMPLE_DA_MAJOR, “DA_ctl”, &DA_ctl_ops);Showversion();If(ret<0){ printk(“pxa270 init_module failed with %dn [--kernel--]”,ret);return ret;} else { printk(“pxa270 serial_led_driver register success!![--kernel--]n”);} return ret;
補充代碼9:
int ret =-ENODEV;#ifdef OURS_DA_DEBUG printk(“pxa270_DA_CTL_init [--kernel--]n”);#endif ret = HW_DA_CTL_init();if(ret)return ret;return 0;
補充代碼10:
#ifdef OURS_DA_DEBUG printk(“cleanup_DA_ctl [--kernel--]n”);#endif devfs_unregister_chrdev(SIMPLE_DA_MAJOR, “DA_ctl”);補充代碼11:
MODULE_DESCRIPTION(“serial_led driver module”);MODULE_AUTHOR(“liduo”);MODULE_LICENSE(“GPL”);module_init(pxa270_DA_CTL_init);module_exit(cleanup_DA_ctl);
二、Makefile文件可以繼續用前面程序Mekefile的代碼,只需要將相應部分的代碼修改即可。
三、作業代碼
要求:輸出三角波。代碼:(需要修改部分)
//---------------------print--------------------void da_create_sin(int fd){ unsigned char buf[(int)POINT];unsigned char*c;unsigned long I;int j;double x;for(j=0;j
x=(j/POINT)*(5*M_PI);//此處原來為x=sin((j/POINT
//*(2*M_PI))#ifdef OURS_DEBUG printf(“%ft”,x);#endif buf[j] =(unsigned char)255*(x/2+1)/2;#ifdef OURS_DEBUG printf(“%xn”, buf[j]);#endif } printf(“create sin waven”);printf(“Use”Ctrl + c“quit the functionn”);while(1){ c = buf;for(j=0;j
四、測試顯示:(以下為三角波)
(以下為sin)
三、實驗總結:
在本次嵌入式實驗中,我們首先在老師的指導下了解了嵌入式系統,初步接觸了Linux環境。我們的實驗板是OURS-PXA270-EP,它是一款基于INTEL XSCALE PXA270處理器,針對高校嵌入式系統教學和實驗科研的平臺。這款設備主要包括核心板與底板兩個部分,核心板主要集成了高速的PXA270 CPU,配套的存儲器,網卡等設備;底板主要是各種類型的接口與擴展口。
了解了實驗的平臺后,在接下來的基本實驗中我們學會了嵌入式開發系統硬件環境的搭建、Linux操作系統RedHat9的安裝、軟件環境的搭建,以及配置超級終端,配置通訊服務。這些實驗內容只要按照實驗指導書上的步驟一步一步做即可,不會出現難以解決的問題,一般都會做的很順利。有三個需要注意的地方時,在配置端口時,一定要確定實驗箱接的是端口一,還是端口二。否則會出現無法建立呼叫的問題(其表現為超級終端接口內沒有輸出內容)。其次要確定虛擬機上網橋的設定是否正確。不然也會出現無法呼叫現象。最后,要確定網線是否連接上。在實驗時,由于有些電腦的網線接口有斷裂的現象,如果插口沒接好的話,將會出現nfs連接錯誤。
在基本實驗之后,進行的就是接口實驗。總的來說,實驗的難度不大。當然這是建立在對實驗代碼有一定理解的基礎之上的。在實驗十二中,我們對實驗的接口代碼規則已經有了一定的了解。而之后的幾個實驗都是基于實驗十二進行相應的改動即可。所以完成下來難度不是很大。而對應的作業中,我們僅需要對測試代碼進行相應的改寫。在對c語言有一定的了解的前提下,可以很容易相應代碼所實現的功能,僅需要對相應代碼做些修改即可。
不過,值得注意的還有兩點,第一:代碼的編寫一定要符合規則,同時,代碼的輸入要避免輸入錯誤。否則,在需要一次一次編譯一次次查看錯誤一次次改正錯誤,這會是個費時費力的工作。第二:每次實驗時,需要從新設定虛擬機的ip,即每次實驗開始時都需要重復做實驗五實驗六。不然在掛載時會出現無法掛載的現象。
通過這次實驗,我對嵌入式編程有了更深層次的理解,加深了我對理論知識的認識,有助于今后的學習和工作。感謝黃惠英老師的細心指導。
第三篇:北郵數據庫實驗報告
數據庫實驗報告
(三)姓名:學號:班級:
1.用Transact-SQL語句、數據導入、SQL Server Management Studio(企業管理器)輸入的方法對所給定的8張表的數據輸入到數據庫中。自行決定每張表的數據導入辦法,但每種方法各針對二或三張表。
? Transact-SQL語句: 導入department,student, student_course表。
insertinto department select*from openrowset
('microsoft.jep.oledb.4.0','excel 5.0;hdr=yes;database=D:課件數據庫database2.xls',department$);
insertinto student select*from openrowset
('microsoft.jep.oledb.4.0','excel 5.0;hdr=yes;database=D:課件數據庫database2.xls',student$);
insertinto student_course select*from openrowset
('microsoft.jep.oledb.4.0','excel 5.0;hdr=yes;database=D:課件數據庫database2.xls',student_course$);
? 數據導入:
操作:選中數據庫studentsdb,右鍵-任務-導入數據。導入book, class, course表。
SQL Server Management Studio: 操作:右鍵需要編輯的表,選擇編輯前200行。
Teacher:
Teacher_course_class:
導入結果: Book:
Class:
Course:
Department:
Student:
Student_course:
Teacher:
Teacher_course_class:
2.用Transact-SQL向Course表中插入一條記錄,course_name為空,看運行的結果。
SQL語句:
INSERTINTO course VALUES('dep02_s002', null,'dep02_s002', '72', '5', '4');運行結果:
分析:course_name有not null的約束,因此這條語句不能執行。
3.用Transact-SQL修改Course表中credit為5的記錄,將其credit改為7, credit小于4的改為2,看運行的結果。
SQL語句:
update course set credit=7 where credit=5;執行結果:
分析:約束C1指定了credit的范圍為1至6.SQL語句:
update course set credit=2 where credit<4;執行結果:
4.刪除一條學生記錄,看運行結果,對運行結果進行分析。SQL語句:
deletefrom student where student_id='g9940201';執行結果:
分析:因為有參照完整性約束,不能刪除。
5.用Transact-SQL完成將編號為dep04_b001的課程的選修信息插入到一個新的選課信息表中。
SQL語句:
Creattablestudent_course2(course_idchar(20), student_idchar(20)gradeint, creditint, semesterint,school_yearchar(20),primarykey(course_id,student_id));
insertintostudent_course2 select*fromstudent_course wherecourse_id='dep04_b001';執行結果:
6.用Transact-SQL完成刪除單片機原理課程的選課信息,分析運行結果。
SQL語句:
deletefrom student_course where course_id in(select course_id from course
where course_name='單片機原理')執行結果: 分析:所有課程號為dep04_s003的課程被刪除。
本實驗中遇到的問題和解決方法:
本實驗的順利完成需要預先作很多準備工作。以下就是我在遇到缺少組件accessdatabaseengine時的解決過程的記錄。
AccessDatabaseEngine的安裝
accessdatabaseengine用于和office連接,導入導出數據,本實驗中需要導入excel文件。安裝配合office的版本,我安裝的是accessdatabaseengine2017(English)版本。安裝32位版本,因office2016是32位。之前誤操作安裝了不能使用的老舊版本accessdatabaseengine2007,通過控制面板-應用程序卸載將其卸載了。安裝accessdatabaseengine依然報錯,是因為microsoftofficeclicktorun阻礙sqlserver的一些功能,需要將其卸載。這是微軟推出的用于減少office打開速度的應用程序,安裝office2016時會自動安裝上,原理是開機時將一部分內容放到內存中,因此打開文件時會更快一些。檢測自己的office是通過clickto run 還是MSI安裝的,可以在word中點擊文件-賬戶,查看產品信息,如果有下圖中“office更新”這個選項,則說明安裝過click to run。這個程序在控制面板-應用程序中找不到,因此用刪除注冊表的方式卸載。快捷鍵“win+R”輸入“regedit”打開注冊表編輯器,左邊HKEY_CLASSES_ROOT-Installer-Product-00006開頭的選項,有四個。單擊這幾個選項,在右側查看詳細信息,可以看到ProductNam是Microsoft Access database engine 2007(我原來誤安裝的老版本)。刪除之前先備份注冊表。方法一:選中要刪除的文件,右鍵-導出,保存。只保存了要刪除的文件。方法二:注冊表編輯器,文件-導出,保存。保存了注冊表所有信息。這是因為如果誤刪了重要文件會導致嚴重后果,可能需要重裝系統,留此備份是為了可以恢復系統。
備份完之后,選中要刪除的文件(00006開頭的四個),右鍵-刪除即可。回到Access database engine 32位的程序安裝包,安裝。我無法安裝64位,可能是因為office是32位。安裝成功之后就可以在sqlserver中導入excel文件了。
第四篇:北郵嵌入式實驗報告
北京郵電大學
嵌入式系統開發實驗報告
學院:
班級: 姓名: 學號:
序號:
目錄
一、實驗目的..............................................................................................1
二、實驗設備..............................................................................................1
三、基礎實驗(實驗一~實驗七)............................................................1
1.實驗五..................................................................................................1 2.實驗六..................................................................................................1 3.實驗七..................................................................................................1
四、驅動程序..............................................................................................5
1.設備驅動程序的概念..........................................................................5 2.驅動程序結構......................................................................................6 3.設備注冊和初始化..............................................................................7 4.設備驅動程序的開發過程..................................................................8
五、基本接口實驗......................................................................................8
1.實驗十二簡單設備驅動程序..............................................................9 2.實驗十三 CPU GPIO驅動程序設計...................................................9 3.實驗十四中斷實驗...........................................................................10 4.實驗十五數碼管顯示實驗................................................................12 5.實驗十六 LED點陣驅動程序設計...................................................19 6.實驗十七 AD驅動實驗....................................................................23 7.實驗十八 DA驅動實驗....................................................................26
六、實驗中遇到的問題及解決方法........................................................30
七、實驗總結及心得................................................................................31
一、實驗目的
通過實驗熟悉Linux環境,并掌握一些基本接口驅動的寫法和用C語言編寫簡單的實驗程序。學習LINUX開發環境的搭建,通訊配置等。并熟練掌握LINUX驅動程序的編寫及開發流程。對嵌入式系統有進一步的了解。
二、實驗設備
1.一套PXA270EP嵌入式實驗箱
2.安裝Redhat9的宿主PC機,并且配置好ARM Linux的開發環境
三、基礎實驗(實驗一~實驗七)
實驗一~七為基礎實驗,目的是為后續實驗搭建好軟、硬件環境,配置好相關的協議、服務,并通過編寫最簡單的HelloWorld程序進行測試。由于后面的實驗都要依靠前面實驗的配置,故本段只著重敘述實驗七的具體實現。
1.實驗五
實驗五為宿主PC機配置了TFTP服務。TFTP(Trivial File Transfer Protocol)是簡單文件傳輸協議,由于特定開發環境的制約,這一服務是必須的。在配置完成后,每次重啟宿主PC機時,都須先輸入命令:service xinetd restart,以啟動TFTP服務。
2.實驗六
實驗六為宿主PC機配置了NFS服務。NFS(Network File System)指網絡文件系統,它實現了文件在不同的系統間使用。當我們想用遠端檔案時,只需調用“mount”就可以遠端系統掛接在自己的檔案系統之下。每次重啟宿主PC機時,都須先輸入命令:service nfs restart,以啟動nfs服務。
3.實驗七
實驗七通過用c語言編寫的簡單程序HelloWorld,測試前面幾個實驗是否成功配置好環境,從超級終端可以看到HelloWorld程序的運行結果。
實驗步驟如下: 1)硬件連接:
連接宿主 PC 機和一臺 PXA270-RP目標板。2)打開宿主PC 機電源,進入 Linux操作系統。
3)啟動RedHat 9.0 的圖形界面,如下圖,若您是以 root 身份登陸在文本模式下,則輸入命令startx啟動圖形界面。進入RedHat 9.0 圖形界面后,打開一個終端窗(Terminal)。
4)輸入minicom然后回車,minicim設置為115200 8NI無流控。
5)打開PXA270_RP目標板電源,按目標板上的BOOT鍵,在minicom中應該會看到如下圖:
6)在minicom終端窗口中,如圖,輸入下列四條命令 root ifconfig eth 192.168.0.50 up mount-o nolock 192.168.0.100:/ /mnt cd /mnt 此時,先將該窗口最小化,在后面的第 10 操作步驟中還將會回到該窗口中進行操作。
7)宿主機上打開一個終端窗口(Terminal),點擊【紅帽/System Tools/Terminal】啟動終端窗口,輸入下列 4 條命令: ① cd /home
②mkdir HW
③ cd HW
④ vi
HelloWorld.c
/*請您輸入程序 7.1 程序清單*/
此時會顯示一個空白的屏幕,這條命令的含義是,使用 Vi 編輯器,對一個名叫HelloWorld.c的文件進行編輯,我們看到的空白窗口是對文件進行編輯的窗口,如下圖。就像在 Windows系統下面使用寫字板等一樣道理。
在 vi 里面先單擊鍵盤 A 鍵,然后左下角會變成—INSER。輸入程序的時候和其他編輯器是一樣的,如下圖。
當輸入程序完畢后,單擊鍵盤 Esc 鍵,然后按“:”(冒號)此時左下角會出現冒號然后輸入“wq”最后按“Enter”確認存盤退出 vi 編輯器,如下圖。
8)在上面同一個終端窗口中,輸入下列 2 條命令交叉編譯HelloWorld.c源程序,并查看生成的.o 目標文件,如圖 7-10,圖7-11: ①
arm-linux-gcc–oHelloWorldHelloWorld.c ②ls 等到再次出現提示符,代表程序已經正確編譯。如果此步出現錯誤信息,請查看錯誤信息,并且重新編輯原來的 C文件,修改錯誤。直到正確編譯。
9)重新打開第 7 步最小化的開有minicom的終端窗口,即到 PXA270-RP 目標板的mnt目錄下,請您輸入下列 3 條命令,運行HelloWorld編譯成功的HelloWorld目標程序:
① cd home/HW
/*回到minicom中目標板的/mnt/home/HW目錄下*/ ②ls ③./ HelloWorld
/*此時會看到如下圖*/
四、驅動程序
1.設備驅動程序的概念
設備驅動程序實際是處理和操作硬件控制器的軟件,從本質上講,是內核中具有最高特權級的、駐留內存的、可共享的底層硬件處理例程。驅動程序是內核的一部分,是操作系統內核與硬件設備的直接接口,驅動程序屏蔽了硬件的細節,完成以下功能:
?對設備初始化和釋放;
?對設備進行管理,包括實時參數設置,以及提供對設備的操作接口; ?讀取應用程序傳送給設備文件的數據或者回送應用程序請求的數據; ?檢測和處理設備出現的錯誤。
Linux操作系統將所有的設備全部看成文件,并通過文件的操作界面進行操作。對用戶程序而言,設備驅動程序隱藏了設備的具體細節,對各種不同設備提供了一致的接口,一般來說,是把設備映射為一個特殊的設備文件,用戶程序可以像對其他文件一樣對此設備文件進行操作。這意味著:
?由于每一個設備至少由文件系統的一個文件代表,因而都有一個“文件名”。?應用程序通常可以通過系統調用open()打開設備文件,建立起與目標設備的連接。
?打開了代表著目標設備的文件,即建立起與設備的連接后,可以通過read()、write()、ioctl()等常規的文件操作對目標設備進行操作。
設備文件的屬性由三部分信息組成:第一部分是文件的類型,第二部分是一個主設備號,第三部分是一個次設備號。其中類型和主設備號結合在一起惟一地確定了設備文件驅動程序及其界面,而次設備號則說明目標設備是同類設備中的第幾個。
由于Linux 中將設備當做文件處理,所以對設備進行操作的調用格式與對文件的操作類似,主要包括open()、read()、write()、ioctl()、close()等。應用程序發出系統調用命令后,會從用戶態轉到核心態,通過內核將open()這樣的系統調用轉換成對物理設備的操作。
2.驅動程序結構
一個設備驅動程序模塊的基本框架
在系統內部,I/O設備的存取通過一組固定的入口點來進行,入口點也可以理解為設備的句柄,就是對設備進行操作的基本函數。字符型設備驅動程序提供如下幾個入口點:
?
open入口點。打開設備準備I/O操作。對字符設備文件進行打開操作,都會調用設備的open入口點。open子程序必須對將要進行的I/O操作做好必要的準備工作,如清除緩沖區等。如果設備是獨占的,即同一時刻只能有一個程序訪問此設備,則open子程序必須設置一些標志以表示設備處于忙狀態。
?
close入口點。關閉一個設備。當最后一次使用設備完成后,調用close子程序。獨占設備必須標記設備方可再次使用。
?
read入口點。從設備上讀數據。對于有緩沖區的I/O操作,一般是從緩沖區里讀數據。對字符設備文件進行讀操作將調用read子程序。
?
write入口點。往設備上寫數據。對于有緩沖區的I/O操作,一般是把數據寫入緩沖區里。對字符設備文件進行寫操作將調用write子程序。
?ioctl入口點。執行讀、寫之外的操作。
select入口點。檢查設備,看數據是否可讀或設備是否可用于寫數據。select系統調用在檢查與設備文件相關的文件描述符時使用select入口點。
3.設備注冊和初始化
設備的驅動程序在加載的時候首先需要調用入口函數init_module(),該函數最重要的一個工作就是向內核注冊該設備,對于字符設備調用register_chrdev()完成注冊。register_chrdev的定義為:intregister_chrdev(unsigned int major, const char *name, struct file_ operations *fops);其中,major是為設備驅動程序向系統申請的主設備號,如果為0,則系統為此驅動程序動態分配一個主設備號。name是設備名,fops是對各個調用的入口點說明。此函數返回0時表示成功;返回-EINVAL,表示申請的主設備號非法,主要原因是主設備號大于系統所允許的最大設備號;返回-EBUSY,表示所申請的主設備號正在被其他設備程序使用。如果動態分配主設備號成功,此函數將返回所分配的主設備號。如果register_chrdev()操作成功,設備名就會出現在/proc/dvices文件中。
Linux在/dev目錄中為每個設備建立一個文件,用ls–l命令列出函數返回值,若小于0,則表示注冊失敗;返回0或者大于0的值表示注冊成功。注冊以后,Linux將設備名與主、次設備號聯系起來。當有對此設備名的訪問時,Linux通過請求訪問的設備名得到主、次設備號,然后把此訪問分發到對應的設備驅動,設備驅動再根據次設備號調用不同的函數。
當設備驅動模塊從Linux內核中卸載,對應的主設備號必須被釋放。字符設備在cleanup_ module()函數中調用unregister_chrdev()來完成設備的注銷。unregister_chrdev()的定義為:intunregister_chrdev(unsigned int major, const char *name);包括設備注冊在內,設備驅動的初始化函數主要完成的功能是有以下5項。(1)對驅動程序管理的硬件進行必要的初始化。
對硬件寄存器進行設置。比如,設置中斷掩碼,設置串口的工作方式、并口的數據方向等。
(2)初始化設備驅動相關的參數。
一般說來,每個設備都要定義一個設備變量,用以保存設備相關的參數。在這一步驟里對設備變量中的項進行初始化。
(3)在內核注冊設備。
調用register_chrdev()函數來注冊設備。(4)注冊中斷。
如果設備需要IRQ支持,則要使用request_irq()函數注冊中斷。(5)其他初始化工作。
初始化部分一般還負責給設備驅動程序申請包括內存、時鐘、I/O端口等在內的系統資源,這些資源也可以在open子程序或者其他地方申請。這些資源不用時,應該釋放,以利于資源的共享。
若驅動程序是內核的一部分,初始化函數則要按如下方式聲明: int __initchr_driver_init(void);其中__init是必不可少的,在系統啟動時會由內核調用chr_driver_init,完成驅動程序的初始化。
當驅動程序是以模塊的形式編寫時,則要按照如下方式聲明: intinit_module(void)當運行后面介紹的insmod命令插入模塊時,會調用init_module函數完成初始化工作。
4.設備驅動程序的開發過程
由于嵌入式設備由于硬件種類非常豐富,在默認的內核發布版中不一定包括所有驅動程序。所以進行嵌入式Linux系統的開發,很大的工作量是為各種設備編寫驅動程序。除非系統不使用操作系統,程序直接操縱硬件。嵌入式Linux系統驅動程序開發與普通Linux開發沒有區別。可以在硬件生產廠家或者Internet上尋找驅動程序,也可以根據相近的硬件驅動程序來改寫,這樣可以加快開發速度。實現一個嵌入式Linux設備驅動的大致流程如下。
(1)查看原理圖,理解設備的工作原理。一般嵌入式處理器的生產商提供參考電路,也可以根據需要自行設計。
(2)定義設備號。設備由一個主設備號和一個次設備號來標識。主設備號惟一標識了設備類型,即設備驅動程序類型,它是塊設備表或字符設備表中設備表項的索引。次設備號僅由設備驅動程序解釋,區分被一個設備驅動控制下的某個獨立的設備。
(3)實現初始化函數。在驅動程序中實現驅動的注冊和卸載。(4)設計所要實現的文件操作,定義file_operations結構。(5)實現所需的文件操作調用,如read、write等。
(6)實現中斷服務,并用request_irq向內核注冊,中斷并不是每個設備驅動所必需的。
(7)編譯該驅動程序到內核中,或者用insmod命令加載模塊。(8)測試該設備,編寫應用程序,對驅動程序進行測試。
五、基本接口實驗
在完成了基本實驗后,我們開始著手基本接口實驗。在這些實驗中,我們學習如何編寫設備驅動程序,及如何用測試程序檢驗驅動程序是否正確,并通過改寫測試程序正常地對驅動程序進行相關操作。
1.實驗十二 簡單設備驅動程序
本次實驗的任務是編寫一個字符型設備驅動程序,并學習在應用程序中調用驅動。考慮到我們初次接觸驅動程序的編寫,對此還十分陌生,因此指導書中提供了本次實驗所要用到的程序源代碼。雖然這樣一個字符型設備驅動程序并沒有任何實際作用,但是它讓我們輕松掌握了嵌入式驅動的編寫過程,因為復雜繁瑣的驅動,其骨架都是相同的。因此,看懂本實驗的源代碼,學習并模仿其編寫方法,對于后續實驗有著非常重要的意義。
2.實驗十三 CPU GPIO驅動程序設計
在本實驗中,我們要編寫第一個針對實際硬件的驅動程序。我們知道,凡是操作系統控制外部設備,即使是最簡單的硬件電路,也是需要驅動的。本實驗涉及的外部硬件只有電阻和發光二極管。我們使用自己編寫的驅動程序與應用程序控制 GPIO96的電平,通過 LED 的亮滅來判斷,是否 CPU 做出了正確的響應。
補充代碼(1)
//-------------------WRITE-----------------------ssize_tSIMPLE_GPIO_LED_write(struct file * file ,const char * buf, size_t count, loff_t * f_ops){ #ifdef OURS_GPIO_LED_DEBUG printk(“SIMPLE_GPIO_LED_write [--kernel--]n”);
#endif
return count;}
補充代碼(2)
//-------------------OPEN------------------------ssize_tSIMPLE_GPIO_LED_open(structinode * inode ,struct file * file){ #ifdef OURS_GPIO_LED_DEBUG printk(“SIMPLE_GPIO_LED_open [--kernel--]n”);
#endif
MOD_INC_USE_COUNT;
return 0;}
補充代碼(3)
//------------------structfile_operationsGPIO_LED_ctl_ops ={ open:SIMPLE_GPIO_LED_open, read:SIMPLE_GPIO_LED_read, write:SIMPLE_GPIO_LED_write, ioctl:SIMPLE_GPIO_LED_ioctl, release:SIMPLE_GPIO_LED_release, };實驗作業
要求在目標板上LED閃爍產生亮7秒,滅2秒的效果 在測試程序中有這樣一段代碼: while(1){ ioctl(fd,LED_OFF);sleep(1);
sleep(1);while(1){ ioctl(fd,LED_OFF);sleep(2);
sleep(7);} 3.實驗十四
中斷實驗
// 滅2秒 // 亮7秒 ioctl(fd,LED_ON);}
// 休眠1秒
ioctl(fd,LED_ON);只需將上面的代碼改為如下代碼即可:
在理論課中,我們學習了許多中斷方面的知識,包括中斷向量、中斷優先級、中斷過程等。在PXA270系統里,中斷控制器分外部設備和 PXA270X 處理器設備產生的兩個層次的中斷,前者是初級的中斷源,后者是次級中斷源,大量的次級中斷源通常被映射為一個初級中斷源。
補充代碼1 voidshowversion(void){ printk(“*********************************************n”);
printk(“t %s tn”, VERSION);
printk(“*********************************************nn”);
} static intSimpleINT_temp_count = 0;補充代碼2 //-------------------READ------------------------ssize_tSIMPLE_INT_read(struct file * file ,char * buf, size_t count, loff_t * f_ops){
#ifdef OURS_INT_DEBUG
#endif return count;printk(“SIMPLE_INT_read [--kernel--]n”);} 補充代碼3 //-------------------WRITE-----------------------ssize_tSIMPLE_INT_write(struct file * file ,const char * buf, size_t count, loff_t * f_ops){
#ifdef OURS_INT_DEBUG
} 補充代碼4 //------------------structfile_operationsINT_ctl_ops ={ open: SIMPLE_INT_open, read: SIMPLE_INT_read, #endif return count;printk(“SIMPL_INT_write [--kernel--]n”);write:SIMPLE_INT_write, ioctl:SIMPLE_INT_ioctl, release:SIMPLE_INT_release, };
通過此實驗,我了解了硬件中斷管腳與中斷號的對應關系,以及中斷號與中斷處理程序的對應關系,對于今后編寫更為復雜的中斷程序打下基礎。
4.實驗十五
數碼管顯示實驗
在此實驗中,我們要編寫針對 74LV164 的驅動程序,并用其串并轉換功能來控制八段LED數碼管的顯示。
補充代碼1 voidshowversion(void){ printk(“*********************************************n”);
printk(“t %s tn”, VERSION);
printk(“*********************************************nn”);
} 補充代碼2 //-------------------READ------------------------ssize_tSERIAL_LED_read(struct file * file ,char * buf, size_t count, loff_t * f_ops){ #ifdef OURS_HELLO_DEBUG
} 補充代碼3 //-------------------WRITE-----------------------ssize_tSERIAL_LED_write(struct file * file ,const char * buf, size_t count, loff_t * f_ops)return count;printk(“SERIAL_LED_read [--kernel--]n”);#endif { #ifdef OURS_HELLO_DEBUG
} 補充代碼4 //-------------------IOCTL-----------------------ssize_tSERIAL_LED_ioctl(structinode * inode ,struct file * file, unsigned intcmd, long data){ #ifdef OURS_HELLO_DEBUG
#endif
} 補充代碼5 //-------------------OPEN------------------------ssize_tSERIAL_LED_open(structinode * inode ,struct file * file){ #ifdef OURS_HELLO_DEBUG
#endif
return 0;} MOD_INC_USE_COUNT;printk(“SERIAL_LED_open [--kernel--]n”);return 0;printk(“SERIAL_LED_ioctl [--kernel--]n”);return count;#endif write_byte(* buf);printk(“SERIAL_LED_write [--kernel--]n”);補充代碼6 //-------------------RELEASE/CLOSE---------------ssize_tSERIAL_LED_release(structinode *inode ,struct file * file){ #ifdef OURS_HELLO_DEBUG
printk(“SERIAL_LED_release [--kernel--]n”);
#endif MOD_DEC_USE_COUNT;return 0;} 補充代碼7 //------------------structfile_operationsSERIAL_LED_ops ={ open: SERIAL_LED_open,read: SERIAL_LED_read,write:SERIAL_LED_write,ioctl:SERIAL_LED_ioctl,release:SERIAL_LED_release, };補充代碼8 staticint __initHW_SERIAL_LED_init(void){ int ret =-ENODEV;
ret =
devfs_register_chrdev(SERIAL_LED_MAJOR, &SERIAL_LED_ops);
showversion();if(ret < 0)“serial_led_ctl”,} {
} else { } return ret;printk(“ pxa270 serial_led_driver register success!![--kernel--]n”);printk(“ pxa270 init_module failed with %dn [--kernel--]”, ret);return ret;補充代碼9 staticint __init pxa270_SERIAL_LED_init(void){ int ret =-ENODEV;
printk(“pxa270_SERIAL_LED_init [--kernel--]n”);
#endif
ret = HW_SERIAL_LED_init();if(ret)return ret;return 0;} 補充代碼10 static void __exit cleanup_SERIAL_LED(void){ #ifdef OURS_HELLO_DEBUG #ifdef OURS_HELLO_DEBUG
#endif }
補充代碼11 MODULE_DESCRIPTION(“serial_led driver module”);
MODULE_AUTHOR(“liduo”);
MODULE_LICENSE(“GPL”);
module_init(pxa270_SERIAL_LED_init);module_exit(cleanup_SERIAL_LED);使用測試程序看到的測試結果是數碼管按0-9顯示輸出。實驗作業要求在上述基礎上,分別實現一下兩個功能:
①要求您再編寫一個測試程序,實現 PXA270-EP 目標板上的 LED 數碼管循環顯示的數字9-0。
②要求您再編寫一個測試程序,實現 PXA270-EP 目標板上的 LED 數碼管循環顯示的數字02468。
由于在測試程序中定義了數組buf[10]分別存儲了0-9是個數,因此上述功能的實現方法是,分別對測試程序做如下修改:
原測試程序: while(1){ for(count=0;count<10;count++){ data[0] = buf[count];ret=write(fd,data,1);sleep(1);} } 實現功能①: while(1){ for(count=9;count>=0;count--)} } 結果顯示
// 倒序顯示數字
{ data[0] = buf[count];ret=write(fd,data,1);sleep(1);devfs_unregister_chrdev(SERIAL_LED_MAJOR, “serial_led”);printk(“cleanup_SERIAL_LED [--kernel--]n”);實現功能②: while(1){ for(count=0;count<9;count=count+2)} } 結果顯示
// 更改顯數順序
{ data[0] = buf[count];ret=write(fd,data,1);sleep(1);
通過更改顯數的順序,很容易實現實驗作業里要求的功能。
5.實驗十六 LED點陣驅動程序設計
通過本實驗的操作,我們將 8X8 的點陣 LED 驅動起來并通過編寫測試程序,使其能夠按照您的意圖進行顯示。要求您還編寫更多的測試程序
補充代碼1 voidshowversion(void){ printk(“*********************************************n”);printk(“t %s tn”, VERSION);printk(“*********************************************nn”);
} 補充代碼2 //-------------------READ------------------------ssize_tSIMPLE_LED_read(struct file * file ,char * buf, size_t count, loff_t * f_ops){ #ifdef OURS_LED_DEBUG
#endif return count;printk(“SIMPLE_LED_read [--kernel--]n”);} 補充代碼3 //-------------------IOCTL-----------------------ssize_tSIMPLE_LED_ioctl(structinode * inode ,struct file * file, unsigned intcmd, long data){
#endif
} 補充代碼4 //------------------structfile_operationsLED_ctl_ops ={ open: SIMPLE_LED_open, read:
SIMPLE_LED_read, write: SIMPLE_LED_write, ioctl: SIMPLE_LED_ioctl, release:SIMPLE_LED_release, };補充代碼5 staticint __init pxa270_LED_CTL_init(void){ int ret =-ENODEV;
printk(“pxa270_LED_CTL_init [--kernel--]n”);
#endif
ret = HW_LED_CTL_init();if(ret)
return ret;#ifdef OURS_LED_DEBUG return 0;printk(“SIMPLE_LED_ioctl [--kernel--]n”);#ifdef OURS_LED_DEBUG return 0;} 補充代碼6 static void __exit cleanup_LED_ctl(void){
#ifdef OURS_LED_DEBUG
#endif
} ①要求您再編寫一個測試程序,實現按橫的方向隔行順序掃描 LED 點陣數碼管。
②要求您再編寫一個測試程序,實現按豎的方向順序掃描 LED 點陣數碼管。作業一,隔行掃描:
printk(“cleanup_LED_ctl [--kernel--]n”);outw(0x0000,ioremap_addr);
devfs_unregister_chrdev(SIMPLE_LED_MAJOR, “led_ary_ctl”);for(i=1;i<=8;i2++){
buf[0]=c;buf[1]=~r;// row for(j=1;j<=8;j++){
} r = 1;c = c<<1;
write(fd,buf,2);
printf(“buf[0],buf[1]: [%x,%x]n”,buf[0],buf[1]);usleep(200000);// sleep 0.2 second r=r<<1;
buf[1]=~r;// column
結果顯示
作業二,豎向掃描:
for(i=1;i<=8;i++){
buf[0]=c;buf[1]=~r;// row for(j=1;j<=8;j++){
} r = 1;c = c<<1;
write(fd,buf,2);
printf(“buf[0],buf[1]: [%x,%x]n”,buf[0],buf[1]);usleep(200000);// sleep 0.2 second r=r<<1;
buf[1]=~r;// column
結果顯示
6.實驗十七 AD驅動實驗
通過本實驗的操作,我們將 AD 轉換器驅動起來并通過編寫測試程序,使其能夠將模擬信號量按照我們的要求轉換成數字信號量。為了更加清楚地理解 AD 轉換器的工作過程,請您再編寫一個測試程序,將 UCB_ADC_INP_AD0 換成其他通道,來觀察其他 AD 通道情況。
補充代碼1 voidshowversion(void){ printk(“%sn”,VERSION);} struct ucb1x00 *ad_ucb;
補充代碼2 //-------------------READ------------------------staticssize_tadctl_read(struct file * file ,char *buf, size_t count, loff_t *offset){
} 補充代碼3 //-------------------WRITE-----------------------ssize_tadctl_write(struct file * file ,const char *buf, size_t count, loff_t *offset){
#ifdef OURS_HELLO_DEBUG printk(“writen”);
#endif
} 補充代碼4 //-------------------OPEN------------------------ssize_tadctl_open(structinode * inode ,struct file * file){
#ifdef OURS_HELLO_DEBUG printk(“openn”);
#endif
}
補充代碼5 //-------------------RELEASE/CLOSE---------------ssize_tadctl_release(structinode *inode ,struct file * file){
#ifdef OURS_HELLO_DEBUG printk(“releasen”);
#endif return 0;return 0;return count;#ifdef OURS_HELLO_DEBUG printk(“readn”);#endif return count;} 補充代碼6 staticstructfile_operationsadctl_ops = {
};補充代碼7 //-------------------INIT------------------------staticint __initHW_AD_CTL_init(void){
return ret;}
補充代碼8 staticint __init pxa270_AD_CTL_init(void){ int ret =-ENODEV;#ifdef OURS_HELLO_DEBUG int ret =-ENODEV;ret = devfs_register_chrdev(ADCTL_MAJOR, “adctl”, &adctl_ops);showversion();ad_ucb=ucb1x00_get();if(ret < 0){
} else { } adctl_dev_handle = devfs_register(NULL, “ad_ctl”, DEVFS_FL_DEFAULT, printk(“adctl driver register success!n”);printk(“fail %dn”,ret);return 0;read: ioctl: adctl_read, adctl_ioctl, write: adctl_write, open: adctl_open, release:adctl_release,ADCTL_MAJOR, 0, S_IFCHR, &adctl_ops, NULL);printk(“initn”);#endif ret=HW_AD_CTL_init();if(ret)}
補充代碼9 static void __exit cleanup_AD_ctl(void){
}
7.實驗十八 DA驅動實驗
通過本實驗的操作,我們使用示波器看到了通過DA轉換而輸出的波形。在此基礎上,要求試寫一個實現輸出三角波的測試程序。
補充代碼1 #include
} printk(“t %st n”,VERSION);printk(“*****************************n”);static long ioremap_addr;補充代碼3 //-------------------READ------------------------ssize_tSIMPLE_DA_read(struct file * file ,char * buf, size_t count, loff_t * f_ops){ #ifdef OURS_DA_DEBUG
} 補充代碼4 //-------------------WRITE-----------------------ssize_tSIMPLE_DA_write(struct file * file ,const char * buf, size_t count, loff_t * f_ops){
printk(“SIMPLE_DA_write[--kernel--]n”);
#endif
return count;} 補充代碼5 //-------------------IOCTL-----------------------ssize_tSIMPLE_DA_ioctl(structinode * inode ,struct file * file, unsigned intcmd, outb(buf[0],ioremap_addr);#ifdef OURS_DA_DEBUG return count;#endif printk(“SIMPLE_DA_read[--kernel--]n”);long data){ #ifdef OURS_DA_DEBUG
printk(“SIMPLE_DA_ioctl[--kernel--]n”);
#endif return 0;} 補充代碼6 //-------------------OPEN------------------------ssize_tSIMPLE_DA_open(structinode * inode ,struct file * file){
#ifdef OURS_DA_DEBUG printk(“SIMPLE_DA_open [--kernel--]n”);
MOD_INC_USE_COUNT;return 0;
#endif } 補充代碼7 /------------------structfile_operationsDA_ctl_ops ={
read: SIMPLE_DA_read,};
補充代碼8 release:
SIMPLE_DA_release, ioctl:
SIMPLE_DA_ioctl, write:
SIMPLE_DA_write, //-------------------INIT------------------------staticint __initHW_DA_CTL_init(void){ int ret =-ENODEV;
}
補充代碼9 staticint __init pxa270_DA_CTL_init(void){ int ret =-ENODEV;
printk(“pxa270_DA_CTL_init [--kernel--]n”);
#endif #ifdef OURS_DA_DEBUG } printk(“ pxa270 led_driver register success!![--kernel--]n”);{ else } return ret;printk(“ pxa270: init_module failed with %dn [--kernel--]”, ret);{ if(ret < 0)showversion();ret = devfs_register_chrdev(SIMPLE_DA_MAJOR, “da_ctl”, &DA_ctl_ops);
ret = HW_DA_CTL_init();if(ret)
return ret;return 0;} 補充代碼10 static void __exit cleanup_DA_ctl(void){
#endif } 補充代碼11 MODULE_DESCRIPTION(“DA_ctl driver module”);MODULE_AUTHOR(“liduo”);MODULE_LICENSE(“GPL”);module_init(pxa270_DA_CTL_init);module_exit(cleanup_DA_ctl);printk(“cleanup_DA_ctl [--kernel--]n”);#ifdef OURS_DA_DEBUG
六、實驗中遇到的問題及解決方法
每一次上課重新啟動后,當需要將宿主PC機的根目錄掛在到PXA270-EP目標板的mnt目錄下(即在超級終端中輸入命令“mount –o soft,timeo=100,rsize=1024 192.168.0.100:/ /mnt”)時,常顯示無法掛載。
解決方法:在超級終端下的掛載命令應該用”mount –o nolock 192.168.0.100:/ /mnt”,如果依然不能掛載需要重啟NFS服務,即在PC機終端中輸入命令”service nfs restart”兩遍后就可以掛載,當然有時候也可能是因為網線沒插好。
在每次重啟機器之后都需要將PC機終端的IP地址和開發板中的系統的IP地址設定正確,不然也無法掛載。
七、實驗總結及心得
本學期的所有實驗均在宿主PC機與PXA270-EP目標板上進行。在實驗中,我們先建立硬件實驗平臺,又建立主機軟件開發環境,接著為實驗進行各項配置,最后完成了各個實驗中的多種功能。值得注意的是,前期的硬件、軟件準備必須完整無誤地實現,后續的實驗才能順利進行。所以,打基礎的工作一定要仔細謹慎。后續實驗中雖然給出了驅動程序的框架,仍需要我們自己補充完整,并開動腦筋舉一反三,在原代碼的基礎上進行一定修改以實現新的功能。
通過這學期的實驗,我逐步完成了建立實驗軟件開發平臺,搭建實驗編譯軟件環境,在PC上編輯、編譯一個應用程序,并且在嵌入式系統上運行和調試它的過程。在實驗中,不難發現,編譯驅動程序大體框架都是一樣的,比如里面的讀函數、寫函數、ioctl函數、打開、關閉以及函數模塊的初始化并且在超級終端上顯示出等。但所不同的是,要根據不同的實驗要求修改名稱,并且對其中必要的部分進行修改。
除此之外,我認為很多基礎知識對實驗的進行也起著非常大的作用,例如數碼管的顯示原理。在掌握了基礎知識之后,上機的過程會顯得相對簡單,尤其是代碼框架已經給出,我們所以需要做的就是根據需要稍作改動來得到我們想要的結果。
在實驗過程中常常會遇到各種各樣的問題,剛開始時我不知如何是好,只能求助于老師和同學,后來隨著實驗的進行,我對實驗的內容和虛擬機都有了一定的了解,遇到問題時也可以靜下心來思考其原因,自己嘗試各種方法去解決問題。整個實驗讓我了解了一套完整的嵌入式系統驅動程序開發的全過程,學到的內容非常豐富,相信在學習了這些內容后,在今后的學習工作中接觸到類似內容,我不會感到無從下手,而是能夠有條不紊。
感謝老師的辛勤指導!
第五篇:北郵信通院移動通信實驗報告
北京郵電大學 移動通信實驗報告
班級:
2010211126
專業:
信息工程
姓名:
學號:
班內序號:
一、實驗目的
1、移動通信設備的認知 a)了解機柜結構
b)了解移動通信設備組成和機框結構 c)了解移動通信設備各單元的功能及連接方式
2、網管操作和 OMT 創建小區 a)了解OMC系統的基本功能和操作 b)掌握OMT如何創建小區
3、移動通信業務的建立與信令流程 a)了解TD-SCDMA系統的網絡結構 b)掌握基本業務測試環境的搭建
c)掌握CS業務與普通PS業務信令流程,體驗視頻通話
二、實驗設備
TD‐SCDMA 移動通信設備一套
三、實驗內容
1、TD_SCDMA系統認識
聽了老師的講授后,我了解到了TD_SCDMA系統是時分雙工的同步CDMA系統,知道了TD_SCDMA系統網絡結構中的三個重要接口(Iu接口、Iub接口、Uu接口),認識了TD_SCDMA系統的物理層結構,熟悉了TD_SCDMA系統的六大關鍵技術以及其后續演進LTE。
2、CN開卡
開卡過程如下圖所示:
3、硬件認知
1)整套移動通信設備如下:
2)RNC設備認知
TDR3000設備機框外形結構如圖1和圖2所示
機框主要功能如下:
支持 14 個板位,作為19〞機框通用背板使用。
滿足 PICMG3.0、PICMG3.1 規范。
實現機框內以太交換雙星型物理連接拓撲。
對各前插板提供板位編號(HA0~7)。
對各前插板提供 Fabric、Base、CLK、Update 數據通路。
提供對所有 FRU 單元的IPMB 總線通路。
提供‐48V 冗余供電通路。
ATCA 機框的UPDATE CHANNEL 設計規則為物理板位1 與13、2 與14、3 與11、4 與12、5 與 9、6 與10、7 與8 兩兩之間設計UPDATE CHANNEL。
圖 1:機框背板功能分布示意圖
由上圖可知,ATCA 機框的UPDATE CHANNEL 設計規則為物理板位1 與13、2 與14、3 與11、4 與12、5 與9、6 與10、7 與8 兩兩之間設計UPDATE CHANNEL。其中藍色連線表示具有Update Channel 連線的板位分配,物理板位7,8 固定為兩塊交換板,其余板位固定為功能板。
圖 2:機框背板接口后視圖
機框物理上是一種13U 標準的ATCA 插箱,機框背板主體尺寸為ATCA 標準定義部分: 354.8mmX426.72mm。主體之下為背板的風扇、電源接口引入部分,風扇接口包括風扇電源和IPMI 接口,背板與電源模塊之間的電源接口包括兩路-48V 供電和四路風扇電源輸入。背板與各前插
板之間的電源接口采用分散供電方式,每個前插板有兩路‐48V 供電。背板下部左右兩部分中間位
置各預留1 英寸安裝輸入電源插座(‐48V/風扇電源)。
單板結構
單板相關描述中,采用“邏輯板(物理板)”的描述方式,其中邏輯板為從軟件功能及操作維護臺顯示的單板;物理板為硬件單板,其單板名稱印刷在在物理單板面板下方。采用該表達方式的目的,是便于使用者能隨時直觀地了解邏輯板與物理板的映射關系,避免不熟悉兩種單板類型映射關系的用戶頻繁地查找單板對應關系表。TDR3000 各種單板的類型及功能如下
機框槽位布局如下:
可以使用LDT軟件查看硬件是否正常,由下圖可以看出,硬件連接均正常。
其中使用的各單板功能如下:
? GCPA(GMPA+SPMC+HDD)全局控制處理板完成以下功能:
? 全局處理板完成 RNC 全局資源的控制與處理、以及與OMC‐R 的連接。全局控制板 支持板載2.5〞 IDE 80GB 硬盤數據存儲功能;
? 處理以下協議:RANAP 協議中的復位,資源復位,過載控制消息;SCCP 管理、MTP3B 管理、ALCAP 管理、M3UA 管理協議等; ? 兩塊 GCPA 以主備用方式工作; ? RSPA(GMPA+SPMC)無線網絡信令處理板完成以下功能:
? 處理 Iu,Iub 接口的控制面協議以及傳輸網絡高層協議,完成無線網絡協議的處理,以及呼叫處理功能;
? 處理的協議有:RRC 協議,RANAP 部分協議,NBAP 協議,無線資源管理;SCCP 部 分協議,ALCAP 部分協議,MTP3B 部分協議,M3UA 部分協議,SCTP 協議等; ? 兩塊 RSPA 以主備用方式工作;
? ONCA/IPUA(MNPA+GEIC)板的主要功能如下:
? ONCA/IPUA(MNPA+GEIC)配合GEIB 后插板完成4xFE/GE 接口功能。? 網絡處理器完成外部 IP 到內部IP 的轉換、處理功能; ? TCSA(MASA)板的主要功能如下:
? 支持控制面 Base 交換和業務面Fabric 交換兩級交換,完成業務和控制面的L2、L3 以太交換功能;
? 固定使用 2 個交換板槽位,即框中的第7、8 槽位;
? 同時完成整個機框的 ShMC(機框管理器)功能,同時兼容IPMC 功能,可根據不同 ATCA 機框進行靈活配置;
? 提供架框號的編碼配置功能;
? 支持對網同步時鐘的接入、分配功能; ? 以主備用方式工作; ? RTPA(MDPA)板由單板控制模塊、單板以太交換模塊、DSP 處理模塊、電源模塊、IPMC 模塊組成,主要功能如下:
? 單板控制模塊完成板內的各種控制管理功能;
? 單板以太交換模塊實現完成 RTPA(MDPA)板內的以太數據交換;
? DSP 處理模塊主要由DSP 和其外圍來實現,完成業務數據和協議的處理;
? 電源轉換模塊從背板接入雙路‐48V 電源,經過電源轉換芯片轉換后,給單板提供各 種芯片正常工作的各種電壓;
? IPMC 模塊主要完成單板上電的控制,以及溫度、電壓監控等功能。? PTPA(MNPA)板的主要功能如下: ? 完成 Iu‐PS 用戶面協議處理功能;
? GTPU 處理板,完成IP(OA)、UDP、TCP、GTP‐U 協議模塊處理; ? Host 部分完成網絡處理器運行狀態監視、性能統計等功能。
3)Node B設備
EMB5116 基站主要分為如下幾個主要組成部分:主機箱、電源單元、EMx 板卡、風機及濾網單元、功能板卡
硬件單元排布如圖3所示。
圖 3:1EMB5116 槽位框圖
4、LMT-B 使用LMT-B軟件進行網絡布配,完成光纖與RRU的配置 1)單天線模式配置 配置參數見下圖:
圖表 4: 單天線模式配置詳細參數
圖表 5:單天線模式配置結果
2)分布式單天線模式配置: 配置參數見下圖:
圖表 6:分布式天線模式配置詳細參數
圖表 7:分布式天線配置結果
3)智能天線模式配置參數如下:將天線模式改為智能天線,并需要在連接天線處添加天線,其它參數與單天線相同。添加的天線信息如下:
圖表 8:所添加天線信息
圖表 9:智能天線模式配置詳細參數
圖表 10:智能天線配置結果
5、LDT信令跟蹤
圖 11:設備監視圖
圖表 12:信令跟蹤結果
6、網管操作和OMT創建小區
實驗步驟: 增加一個 R4 小區
選擇邏輯基站—小區集—右鍵選擇快速創建小區
第一步:
小區基本信息: 小區標識(CellId):
同一個RNC 中的CellId 配置值要求不能重復; 小區參數標識(CellParameterId):
小區參數標識ID 唯一標識了小區中的一組參數:下行同步序列SYNC‐DL、上行同步
序列SYNC‐UL sequences、擾碼、midamble 碼;
小區特性:
主頻段時隙轉換點:3(說明小區時隙為2 上4 下,一般為2 上4 下); 其他頻段時隙轉換點:可以與主頻段不一致;
HSDPA 特性:
非HSDPA 小區(可根據需要選擇:HSDPA 小區或混合DPA 小區,這里我們選擇非HSDPA 小
區是因為我們要創建一個R4 小區); HSUPA 特性:
不支持HSUPA 小區(可根據需要選擇支持HSUPA 小區,這里我們選擇不支持HSUPA 小區
是因為我們要創建一個R4 小區);
位置區信息:
位置區代碼:由RNC 全局參數決定(實驗室環境與RNC 一致:比如RNC2,那么就是2);
路由區代碼:由RNC 全局參數決定(實驗室環境與RNC 一致:比如RNC2,那么就是2);
服務區代碼:實驗室環境為107; UPA 有效數:1(固定);
其他信息默認,然后選擇下一步
第二步:
根據需要選擇輔載波的數量;
主載波上行時隙至少要選擇一個PRACH; 然后選擇下一步;
第三步:
信道功率信息和UpPCH 信道功率信息選擇默認即可,這些數值在創建完小區之后,根據需要 是可以修改的;
選擇完成,一個R4 小區創建完畢。
四、實驗總結
此次實驗不僅讓我更加深入的了解了TD_SCDMA系統,還認識了許多和移動通信有關的設備,體驗了視頻通話和手機電視等先進的移動通信技術,極大的增強了我對移動通信的興趣。