|
1.指向函数的指针 指针不光能指向变量、字符串、数组,还能够指向函数。在C语言中允许将函数的入口地址赋值给指针。这样就可以通过指针来访问函数。 还可以把函数指针当成参数来传递。函数指针可以简化代码,减少修改代码时的工作量。通过接下来的讲解大家会体会到这一点的。 /*函数指针简单讲解*通过指向函数的指 *针调用比较两个数 *大小的程序 */ & z) D8 v5 p9 e #include <iostream>! x) B7 D9 K5 @: v+ g1 _* @- z using namespace std; /*比较函数声明*/ int max(int,int);- ^' l$ p( s0 @3 Y$ R /*指向函数的指针声明(此刻指针未指向任何一个函数)*/ int (*test)(int,int); int main(int argc,char* argv[])7 J3 u p. Z0 e! X" N {" p! R5 S) e% Y O# k int largernumber; ) } s0 R2 t& E+ w9 X /*将max函数的入口地址赋值给 *函数指针test */ test=max; 7 O0 V$ w% \" D! F9 | /*通过指针test调用函数max实! ^9 J( d7 A% L- p *现比较大小8 l3 ?. p+ k) z0 ~$ T- s */: f# |' p- D6 f6 ?8 ]- K2 d6 z largernumber=(*test)(1,2);, [: s$ e: ^7 }* h! m3 t cout<<largernumber<<endl; return 0; }7 `0 c; z0 }( S! c int max(int a,int b) { return (a>b?a:b); } 通过注释大家应该很容易理解,函数指针其实和变量指针、字符串指针差不多的。如果大家理解了这个小程序,那么理解起下面这个有关Nand flash的源代码就好多了。 typedef struct {3 j% d4 O, @1 v- Cvoid (*nand_reset)(void);/ B- a' T5 ?) L [* V. R. U. T void (*wait_idle)(void); void (*nand_select_chip)(void);# n* @% O h3 Z/ r void (*nand_deselect_chip)(void);3 |2 U( H6 G; i; R' b void (*write_cmd)(int cmd); void (*write_addr)(unsigned int addr); unsigned char (*read_data)(void); }t_nand_chip; static t_nand_chip nand_chip;: }2 l3 K6 I4 e! N& C" v' A ; V: H% ^* b- |4 {" C. k0 s2 A /* NAND Flash操作的总入口, 它们将调用S3C2410或S3C2440的相应函数 *// K/ F9 X' k! ~6 B. _2 U static void nand_reset(void);6 B4 A N4 ^$ u4 m5 { static void wait_idle(void); @$ m9 G- t0 T7 I5 U5 [+ X2 ] static void nand_select_chip(void);) |- b" p, A4 N4 y- A3 _1 H2 N' j static void nand_deselect_chip(void); static void write_cmd(int cmd); static void write_addr(unsigned int addr); static unsigned char read_data(void); $ l& f% B% k( t4 ^; B& ] /* S3C2410的NAND Flash处理函数 */ static void s3c2410_nand_reset(void); static void s3c2410_wait_idle(void);$ T! L- P/ D9 w# @" V7 k static void s3c2410_nand_select_chip(void);$ C' ^5 o" N* F& ~. w static void s3c2410_nand_deselect_chip(void); static void s3c2410_write_cmd(int cmd);2 Q' B8 X% N& U# G4 a) |& h) Y static void s3c2410_write_addr(unsigned int addr);' ~9 u: [5 m5 }( ?! t: }' R static unsigned char s3c2410_read_data(); ) Q% |/ e; L( n /* S3C2440的NAND Flash处理函数 */& n B+ u8 S" |$ i; \: W) r static void s3c2440_nand_reset(void); static void s3c2440_wait_idle(void);5 z, U$ |" C2 L; Q; u; w static void s3c2440_nand_select_chip(void); static void s3c2440_nand_deselect_chip(void); static void s3c2440_write_cmd(int cmd);0 h" ]! [9 _) F! m4 c static void s3c2440_write_addr(unsigned int addr);0 u2 o+ S7 c3 `& t static unsigned char s3c2440_read_data(void); * S: v8 s. `( ?2 H5 W9 ~6 c, W" q 8 i* t: u }* S. \1 {7 e /* 初始化NAND Flash */; Y- V5 R% y6 ~! f1 a* Z! l void nand_init(void)" l' U/ ?2 v& S { #define TACLS 0 #define TWRPH0 3 #define TWRPH1 05 A6 d+ T. n- c3 W5 ] , @- O6 o, \8 X6 |0 H7 { /* 判断是S3C2410还是S3C2440 */: u' f1 Y# F, k- E if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002)) {+ ^+ h" v) H3 V7 o" C nand_chip.nand_reset = s3c2410_nand_reset; nand_chip.wait_idle = s3c2410_wait_idle; nand_chip.nand_select_chip = s3c2410_nand_select_chip; nand_chip.nand_deselect_chip = s3c2410_nand_deselect_chip; nand_chip.write_cmd = s3c2410_write_cmd;; C# e1 F3 q# Z4 g nand_chip.write_addr = s3c2410_write_addr; nand_chip.read_data = s3c2410_read_data;8 [7 ^) T$ a2 k( @5 j3 q ! Y1 l, V' c }2 o$ @0 b /* 使能NAND Flash控制器, 初始化ECC, 禁止片选, 设置时序 */ s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);7 ] h9 n, h7 s) {, [ e. Z }% ^3 I/ K/ Z- r+ G5 @/ A3 `/ ? else {! D0 b5 p5 [ O4 o6 Z6 P8 H nand_chip.nand_reset = s3c2440_nand_reset;' p- H" D+ F3 @% _ X nand_chip.wait_idle = s3c2440_wait_idle; nand_chip.nand_select_chip = s3c2440_nand_select_chip; nand_chip.nand_deselect_chip = s3c2440_nand_deselect_chip;5 U% u0 [# Q4 B- r; C2 ]7 S! J- B nand_chip.write_cmd = s3c2440_write_cmd;( E6 W5 E6 x. V5 u; v! @ #ifdef LARGER_NAND_PAGE1 ]% R! Z: H7 G1 @6 E nand_chip.write_addr = s3c2440_write_addr_lp;2 t/ U( U0 h4 e #else nand_chip.write_addr = s3c2440_write_addr;+ F* u* `1 P0 R# y% Z #endif/ L* z( j; Q9 i3 f: m6 ? nand_chip.read_data = s3c2440_read_data; /* 设置时序 */ s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4); /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */ s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0); }+ B W/ v9 z1 [9 V8 V /* 复位NAND Flash */9 l# \( m- D, J: f nand_reset();/ w' ]6 \2 Q' { } 这段代码是用于操作Nand Flash的一段源代码。首先我们看到开始定义了一个结构体,里面放置的全是函数指针。他们等待被赋值。然后是定义了一个这种结构体的变量nand_chip。 然后是即将操作的函数声明。这些函数将会被其他文件的函数调用。因为在这些函数里一般都只有一条语句,就是调用结构体的函数指针。接着往下看,是针对两种架构的函数声明。然后在nand_init函数中对nand_chip进行赋值,这也就是我们刚刚讲过的,将函数的入口地址赋值给指针。 现在nand_chip已经被赋值了。如果我们要对Nand进行读写操作,我们只需调用nand_chip.read_data()或者nand_chip.write_cmd()等等函数。这是比较方便的一点,另一点,此代码具有很强的移植性,如果我们又用到了一种芯片,我们就不需要改变整篇代码,只需在nand_init函数中增加对新的芯片的判断,然后给nand_chip赋值即可。所以我说函数指针会使代码具有可移植性,易修改性。 如果大家想对函数指针有更深的理解建议看一下这篇博文:http://www.cnblogs.com/CBDoctor/archive/2012/10/15/2725219.html 写的超赞,博主很佩服^_^ 2.C语言操作寄存器在嵌入式开发中,常常要操作寄存器,对寄存器进行写入,读出等等操作。每个寄存器都有自己固有的地址,通过C语言访问这些地址就变得尤为重要。 #define GSTATUS1 (*(volatile unsigned int *)0x560000B0)* Y0 C* z: U8 a* y- Z* B( ~) L在这里,我们举一个例子。这是一个状态寄存器的宏定义。首先,通过unsigned int我们能够知道,该寄存器是32位的。因为要避免程序执行过程中直接从cache中读取数据,所以用volatile进行修饰。 每次都要重新读取该地址上的值。首先(volatile unsigned int*)是一个指针,我们就假设它为p吧。它存储的地址就是后面的0x560000B0,然后取这个地址的值,也就是p,所以源代码变成了((volatile unsigned int *)0x560000B0),接下来我们就能直接赋值给GSTATUS1来改变地址0x560000B0上存储的值了。 /* NAND FLASH (see S3C2410 manual chapter 6) */typedef struct {: V% @ w9 n- b) [, F S3C24X0_REG32 NFCONF; S3C24X0_REG32 NFCMD;& V9 T$ n: `6 U/ U1 O0 B* r$ T S3C24X0_REG32 NFADDR; S3C24X0_REG32 NFDATA; S3C24X0_REG32 NFSTAT;1 u. a/ c0 K8 }7 J S3C24X0_REG32 NFECC;. o6 I! c9 u$ e9 T+ Z0 G } S3C2410_NAND; static S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000; 4 m0 {% X& w0 R/ S/ Y+ O9 Y7 K5 P1 b volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFSTAT; 有时候,你会看到这样一种情况的赋值。其实这和我们刚刚讲过的差不多。只不过这里是在定义了指针的同时对指针进行赋值。这里首先定义了结构体S3C2410_NAND,里面全部是32位的变量。 又定义了这种结构体类型的指针,且指向0x4e000000这个地址,也就是此刻s3c2410nand指向了一个实际存在的物理地址。s3c2410nand指针访问了NFSTAT变量,但我们要的是它的地址,而不是它地址上的值。所以用&取NFSTAT地址,这样再强制转换为unsigned char型的指针,赋给p,就可以直接通过p来给NFSTAT赋值了。 3.寄存器位操作#define GPFCON (*(volatile unsigned long *)0x56000050)# i2 Y1 U4 T: \GPFCON &=~ (0x1<<3); GPFCON |= (0x1<<3); 结合我们刚刚所讲的,首先宏定义寄存器,这样我们能够直接给它赋值。位操作中,我们要学会程序第2行中的,给目标位清0,这里是给bit3清0。第3行则是给bit3置1。 |
| 发错了 |
微信公众号
手机版