0%

arm面向对象设计(代码组织)

2018年2月9日 下午8:36

注:代码是009_div_017_010这节的内容

回答几个关键问题:

  1. 这个问题由几个部分组成?
    1. 第一部分:给lcd控制器中的寄存器初始化
      1. Lcd.c团体
      2. lcd_controller.c团体
    2. 第二部分:从配置好的寄存器中查出LCD屏的性质,然后编程实现具体内容的输出到LCD屏幕上。
  2. 当前情况的特点?
    1. lcd.c团体代表的是,lcd_controller.c团体代表是方法
    2. lcd.c团体有点像是javaEE中的实体这个概念
  3. 需要的角色,以及各个角色的作用
    1. 【程序的最终目的】:用具体的数值去赋值给lcd控制器的寄存器
    2. 【采用面向对象设计模式的作用目的】:两个团体最主要的目的是实现扩展性,将赋值给寄存器两个部分分开,否则根本分不需要分两个团体
    3. 由扩展性带来的问题
      1. 如何能让多个lcd屏幕(参数),多个lcd控制器(寄存器)有统一的接口
        1. .h文件用来限制。类似于javaEE中的抽象类和接口的作用。
        2. 区别是:一个用结构体保存变量,一个用结构体保存函数指针
      2. 必然每个有各自的管理者,各自管理者要有怎样的功能?。在这里我们分别是lcd.c和lcd_controller.c。
        1. lcd.c
        2. lcd_controller.c
        3. 注:上面的两幅图可以说是整体的一个精华。我一开始就不太理解
          1. 这其中蕴含着一种思考方法🤔:从上层和下层两个方面来思考。
          2. 这种类似于提供接口式的思考方式,可以说是面向对象设计的一个关键点
          3. 在这种注册机制中,有一点要注意:管理者提供了注册方法,这个方法是小弟去调用完成注册的,而不是管理者进行注册!这个问题容易忽略

代码:

lcd_test.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
lcd_test.c

#include "geometry.h"
#include "font.h"

void lcd_test(void)
{
unsigned int fb_base;
int xres, yres, bpp;
int x, y;
unsigned short *p;
unsigned int *p2;

/* 初始化LCD */
lcd_init();

/* 使能LCD */
lcd_enable();

/* 获得LCD的参数: fb_base, xres, yres, bpp */
get_lcd_params(&fb_base, &xres, &yres, &bpp);
fb_get_lcd_params();
font_init();

/* 往framebuffer中写数据 */
if (bpp == 16)
{
/* 让LCD输出整屏的红色 */

/* 565: 0xf800 */

p = (unsigned short *)fb_base;
for (x = 0; x < xres; x++)
for (y = 0; y < yres; y++)
*p++ = 0xf800;

/* green */
p = (unsigned short *)fb_base;
for (x = 0; x < xres; x++)
for (y = 0; y < yres; y++)
*p++ = 0x7e0;

/* blue */
p = (unsigned short *)fb_base;
for (x = 0; x < xres; x++)
for (y = 0; y < yres; y++)
*p++ = 0x1f;

/* black */
p = (unsigned short *)fb_base;
for (x = 0; x < xres; x++)
for (y = 0; y < yres; y++)
*p++ = 0;

}
else if (bpp == 32)
{
/* 让LCD输出整屏的红色 */

/* 0xRRGGBB */

p2 = (unsigned int *)fb_base;
for (x = 0; x < xres; x++)
for (y = 0; y < yres; y++)
*p2++ = 0xff0000;

/* green */
p2 = (unsigned int *)fb_base;
for (x = 0; x < xres; x++)
for (y = 0; y < yres; y++)
*p2++ = 0x00ff00;

/* blue */
p2 = (unsigned int *)fb_base;
for (x = 0; x < xres; x++)
for (y = 0; y < yres; y++)
*p2++ = 0x0000ff;

/* black */
p2 = (unsigned int *)fb_base;
for (x = 0; x < xres; x++)
for (y = 0; y < yres; y++)
*p2++ = 0;

}

delay(1000000);

/* 画线 */
draw_line(0, 0, xres - 1, 0, 0xff0000);
draw_line(xres - 1, 0, xres - 1, yres - 1, 0xffff00);
draw_line(0, yres - 1, xres - 1, yres - 1, 0xff00aa);
draw_line(0, 0, 0, yres - 1, 0xff00ef);
draw_line(0, 0, xres - 1, yres - 1, 0xff4500);
draw_line(xres - 1, 0, 0, yres - 1, 0xff0780);

delay(1000000);

/* 画圆 */
draw_circle(xres/2, yres/2, yres/4, 0xff00);

/* 输出文字 */
fb_print_string(10, 10, "www.100ask.net\n\r100ask.taobao.com", 0xff00);
}

lcd.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
lcd.c
#include "lcd.h"
#include "lcd_controller.h"

#define LCD_NUM 10

static p_lcd_params p_array_lcd[LCD_NUM];
static p_lcd_params g_p_lcd_selected;

int register_lcd(p_lcd_params plcd)
{
int i;
for (i = 0; i < LCD_NUM; i++)
{
if (!p_array_lcd[i])
{
p_array_lcd[i] = plcd;
return i;
}
}
return -1;
}

int select_lcd(char *name)
{
int i;
for (i = 0; i < LCD_NUM; i++)
{
if (p_array_lcd[i] && !strcmp(p_array_lcd[i]->name, name))
{
g_p_lcd_selected = p_array_lcd[i];
return i;
}
}
return -1;
}

void get_lcd_params(unsigned int *fb_base, int *xres, int *yres, int *bpp)
{
*fb_base = g_p_lcd_selected->fb_base;
*xres = g_p_lcd_selected->xres;
*yres = g_p_lcd_selected->yres;
*bpp = g_p_lcd_selected->bpp;
}

void lcd_enable(void)
{
lcd_controller_enable();
}

void lcd_disable(void)
{
lcd_controller_disable();
}

int lcd_init(void)
{
/* 注册LCD */
lcd_4_3_add();

/* 注册LCD控制器 */
lcd_contoller_add();

/* 选择某款LCD */
select_lcd("lcd_4.3");

/* 选择某款LCD控制器 */
select_lcd_controller("s3c2440");

/* 使用LCD的参数, 初始化LCD控制器 */
lcd_controller_init(g_p_lcd_selected);
}

Lcd.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
lcd.h


#ifndef _LCD_H
#define _LCD_H


enum {
NORMAL = 0,
INVERT = 1,
};

/* NORMAL : 正常极性
* INVERT : 反转极性
*/
typedef struct pins_polarity {
int de; /* normal: 高电平时可以传输数据 */
int pwren; /* normal: 高电平有效 */
int vclk; /* normal: 在下降沿获取数据 */
int rgb; /* normal: 高电平表示1 */
int hsync; /* normal: 高脉冲 */
int vsync; /* normal: 高脉冲 */
}pins_polarity, *p_pins_polarity;

typedef struct time_sequence {
/* 垂直方向 */
int tvp; /* vysnc脉冲宽度 */
int tvb; /* 上边黑框, Vertical Back porch */
int tvf; /* 下边黑框, Vertical Front porch */

/* 水平方向 */
int thp; /* hsync脉冲宽度 */
int thb; /* 左边黑框, Horizontal Back porch */
int thf; /* 右边黑框, Horizontal Front porch */

int vclk;
}time_sequence, *p_time_sequence;


typedef struct lcd_params {
char *name;

/* 引脚极性 */
pins_polarity pins_pol;

/* 时序 */
time_sequence time_seq;

/* 分辨率, bpp */
int xres;
int yres;
int bpp;

/* framebuffer的地址 */
unsigned int fb_base;
}lcd_params, *p_lcd_params;

void get_lcd_params(unsigned int *fb_base, int *xres, int *yres, int *bpp);

#endif /* _LCD_H */

lcd_4.3.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
lcd_4.3.c

#include "lcd.h"

#define LCD_FB_BASE 0x33c00000

lcd_params lcd_4_3_params = {
.name = "lcd_4.3",
.pins_pol = {
.de = NORMAL, /* normal: 高电平时可以传输数据 */
.pwren = NORMAL, /* normal: 高电平有效 */
.vclk = NORMAL, /* normal: 在下降沿获取数据 */
.rgb = NORMAL, /* normal: 高电平表示1 */
.hsync = INVERT, /* normal: 高脉冲 */
.vsync = INVERT, /* normal: 高脉冲 */
},
.time_seq = {
/* 垂直方向 */
.tvp= 10, /* vysnc脉冲宽度 */
.tvb= 2, /* 上边黑框, Vertical Back porch */
.tvf= 2, /* 下边黑框, Vertical Front porch */

/* 水平方向 */
.thp= 41, /* hsync脉冲宽度 */
.thb= 2, /* 左边黑框, Horizontal Back porch */
.thf= 2, /* 右边黑框, Horizontal Front porch */

.vclk= 9, /* MHz */
},
.xres = 480,
.yres = 272,
.bpp = 32, /* 16, no 24bpp */
.fb_base = LCD_FB_BASE,
};


void lcd_4_3_add(void)
{
register_lcd(&lcd_4_3_params);
}

Lcd_controller.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
lcd_controller.c

#include "lcd_controller.h"

#define LCD_CONTROLLER_NUM 10

static p_lcd_controller p_array_lcd_controller[LCD_CONTROLLER_NUM];
static p_lcd_controller g_p_lcd_controller_selected;

int register_lcd_controller(p_lcd_controller plcdcon)
{
int i;
for (i = 0; i < LCD_CONTROLLER_NUM; i++)
{
if (!p_array_lcd_controller[i])
{
p_array_lcd_controller[i] = plcdcon;
return i;
}
}
return -1;
}

int select_lcd_controller(char *name)
{
int i;
for (i = 0; i < LCD_CONTROLLER_NUM; i++)
{
if (p_array_lcd_controller[i] && !strcmp(p_array_lcd_controller[i]->name, name))
{
g_p_lcd_controller_selected = p_array_lcd_controller[i];
return i;
}
}
return -1;
}


/* 向上: 接收不同LCD的参数
* 向下: 使用这些参数设置对应的LCD控制器
*/

int lcd_controller_init(p_lcd_params plcdparams)
{
/* 调用所选择的LCD控制器的初始化函数 */
if (g_p_lcd_controller_selected)
{
g_p_lcd_controller_selected->init(plcdparams);
return 0;
}
return -1;
}

void lcd_controller_enable(void)
{
if (g_p_lcd_controller_selected)
{
g_p_lcd_controller_selected->enable();
}
}

void lcd_controller_disable(void)
{
if (g_p_lcd_controller_selected)
{
g_p_lcd_controller_selected->disable();
}
}


void lcd_contoller_add(void)
{
s3c2440_lcd_contoller_add();
}

Lcd_controller.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Lcd_controller.h

#ifndef _LCD_CONTROLLER_H
#define _LCD_CONTROLLER_H

#include "lcd.h"

typedef struct lcd_controller {
char *name;
void (*init)(p_lcd_params plcdparams);
void (*enable)(void);
void (*disable)(void);
}lcd_controller, *p_lcd_controller;

#endif /* _LCD_CONTROLLER_H */

s3c2440_lcd_controller.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
s3c2440_lcd_controller.c

#include "lcd.h"
#include "lcd_controller.h"
#include "../s3c2440_soc.h"

#define HCLK 100

void jz2440_lcd_pin_init(void)
{
/* 初始化引脚 : 背光引脚 */
GPBCON &= ~0x3;
GPBCON |= 0x01;

/* LCD专用引脚 */
GPCCON = 0xaaaaaaaa;
GPDCON = 0xaaaaaaaa;

/* PWREN */
GPGCON |= (3<<8);
}


/* 根据传入的LCD参数设置LCD控制器 */
void s3c2440_lcd_controller_init(p_lcd_params plcdparams)
{
int pixelplace;
unsigned int addr;

jz2440_lcd_pin_init();

/* [17:8]: clkval, vclk = HCLK / [(CLKVAL+1) x 2]
* 9 = 100M /[(CLKVAL+1) x 2], clkval = 4.5 = 5
* CLKVAL = 100/vclk/2-1
* [6:5]: 0b11, tft lcd
* [4:1]: bpp mode
* [0] : LCD video output and the logic enable/disable
*/
int clkval = (float)HCLK/plcdparams->time_seq.vclk/2-1+0.5;
//int clkval = 5;
int bppmode = plcdparams->bpp == 8 ? 0xb :\
plcdparams->bpp == 16 ? 0xc :\
0xd; /* 0xd: 24,32bpp */
LCDCON1 = (clkval<<8) | (3<<5) | (bppmode<<1) ;

/* [31:24] : VBPD = tvb - 1
* [23:14] : LINEVAL = line - 1
* [13:6] : VFPD = tvf - 1
* [5:0] : VSPW = tvp - 1
*/
LCDCON2 = ((plcdparams->time_seq.tvb - 1)<<24) | \
((plcdparams->yres - 1)<<14) | \
((plcdparams->time_seq.tvf - 1)<<6) | \
((plcdparams->time_seq.tvp - 1)<<0);

/* [25:19] : HBPD = thb - 1
* [18:8] : HOZVAL = 列 - 1
* [7:0] : HFPD = thf - 1
*/
LCDCON3 = ((plcdparams->time_seq.thb - 1)<<19) | \
((plcdparams->xres - 1)<<8) | \
((plcdparams->time_seq.thf - 1)<<0);

/*
* [7:0] : HSPW = thp - 1
*/
LCDCON4 = ((plcdparams->time_seq.thp - 1)<<0);

/* 用来设置引脚极性, 设置16bpp, 设置内存中象素存放的格式
* [12] : BPP24BL
* [11] : FRM565, 1-565
* [10] : INVVCLK, 0 = The video data is fetched at VCLK falling edge
* [9] : HSYNC是否反转
* [8] : VSYNC是否反转
* [7] : INVVD, rgb是否反转
* [6] : INVVDEN
* [5] : INVPWREN
* [4] : INVLEND
* [3] : PWREN, LCD_PWREN output signal enable/disable
* [2] : ENLEND
* [1] : BSWP
* [0] : HWSWP
*/

pixelplace = plcdparams->bpp == 32 ? (0) : \
plcdparams->bpp == 16 ? (1) : \
(1<<1); /* 8bpp */

LCDCON5 = (plcdparams->pins_pol.vclk<<10) |\
(plcdparams->pins_pol.rgb<<7) |\
(plcdparams->pins_pol.hsync<<9) |\
(plcdparams->pins_pol.vsync<<8) |\
(plcdparams->pins_pol.de<<6) |\
(plcdparams->pins_pol.pwren<<5) |\
(1<<11) | pixelplace;

/* framebuffer地址 */
/*
* [29:21] : LCDBANK, A[30:22] of fb
* [20:0] : LCDBASEU, A[21:1] of fb
*/
addr = plcdparams->fb_base & ~(1<<31);
LCDSADDR1 = (addr >> 1);

/*
* [20:0] : LCDBASEL, A[21:1] of end addr
*/
addr = plcdparams->fb_base + plcdparams->xres*plcdparams->yres*plcdparams->bpp/8;
addr >>=1;
addr &= 0x1fffff;
LCDSADDR2 = addr;//
}

void s3c2440_lcd_controller_enalbe(void)
{
/* 背光引脚 : GPB0 */
GPBDAT |= (1<<0);

/* pwren : 给LCD提供AVDD */
LCDCON5 |= (1<<3);

/* LCDCON1'BIT 0 : 设置LCD控制器是否输出信号 */
LCDCON1 |= (1<<0);
}

void s3c2440_lcd_controller_disable(void)
{
/* 背光引脚 : GPB0 */
GPBDAT &= ~(1<<0);

/* pwren : 给LCD提供AVDD */
LCDCON5 &= ~(1<<3);

/* LCDCON1'BIT 0 : 设置LCD控制器是否输出信号 */
LCDCON1 &= ~(1<<0);
}

struct lcd_controller s3c2440_lcd_controller = {
.name = "s3c2440",
.init = s3c2440_lcd_controller_init,
.enable = s3c2440_lcd_controller_enalbe,
.disable = s3c2440_lcd_controller_disable,
};


void s3c2440_lcd_contoller_add(void)
{
register_lcd_controller(&s3c2440_lcd_controller);
}