Bonjour,

Toujours sur mon projet Arduino UNI / Shield Ethernet / Ecran TFT tactile

La dalle tactile est SPI mais la bibliothèque URTouch que j'utilise n'utilise que du bitbanging (software SPI).

Je souhaite utiliser le SPI hardware, qui est déjà utilisé avec succès pour le shield Ethernet et l'écran TFT, pour les raisons suivantes :
- libérer des broches I/O
- code plus compact
- mon code ne communique jamais en même temps avec l'écran TFT, la dalle tactile et le shield Ethernet.

J'ai trouvé unce message intéressant mais ancien, et je m'en suis inspiré pour modifier la librairie URTouch

Ancien fichier .h de la librairie :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
/*
  URTouch.h - Arduino/chipKit library support for Color TFT LCD Touch screens 
  Copyright (C)2018 Rinky-Dink Electronics, Henning Karlsen. All right reserved
  
  Basic functionality of this library are based on the demo-code provided by
  ITead studio.
 
  You can find the latest version of the library at 
  http://www.RinkyDinkElectronics.com/
 
  This library is free software; you can redistribute it and/or
  modify it under the terms of the CC BY-NC-SA 3.0 license.
  Please see the included documents for further information.
 
  Commercial use of this library requires you to buy a license that
  will allow commercial use. This includes using the library,
  modified or not, as a tool to sell products.
 
  The license applies to all part of the library including the 
  examples and tools supplied with the library.
*/
 
#ifndef URTouch_h
#define URTouch_h
 
#define URTOUCH_VERSION	202
 
#if defined(__AVR__)
	#include "Arduino.h"
	#include "HW_AVR_defines.h"
#elif defined(__PIC32MX__)
	#include "WProgram.h"
	#include "hardware/pic32/HW_PIC32_defines.h"
#elif defined(__arm__)
	#include "Arduino.h"
	#include "hardware/arm/HW_ARM_defines.h"
#endif
 
#define PORTRAIT			0
#define LANDSCAPE			1
 
#define PREC_LOW			1
#define PREC_MEDIUM			2
#define PREC_HI				3
#define PREC_EXTREME		4
 
class URTouch
{
	public:
		int16_t	TP_X ,TP_Y;
 
				URTouch(byte tclk, byte tcs, byte tdin, byte dout, byte irq);
 
		void	InitTouch(byte orientation = LANDSCAPE);
		void	read();
		bool	dataAvailable();
		int16_t	getX();
		int16_t	getY();
		void	setPrecision(byte precision);
 
		void	calibrateRead();
 
    private:
		regtype *P_CLK, *P_CS, *P_DIN, *P_DOUT, *P_IRQ;
		regsize B_CLK, B_CS, B_DIN, B_DOUT, B_IRQ;
		byte	T_CLK, T_CS, T_DIN, T_DOUT, T_IRQ;
		long	_default_orientation;
		byte	orient;
		byte	prec;
		byte	display_model;
		long	disp_x_size, disp_y_size, default_orientation;
		long	touch_x_left, touch_x_right, touch_y_top, touch_y_bottom;
 
		void	touch_WriteData(byte data);
		word	touch_ReadData();
 
#if defined(ENERGIA)
		volatile uint32_t* portOutputRegister(int value);
		volatile uint32_t* portInputRegister(int value);
#endif
};
 
#endif
Ancien fichier .cpp de la librairie :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
/*
  URTouch.cpp - Arduino/chipKit library support for Color TFT LCD Touch screens 
  Copyright (C)2018 Rinky-Dink Electronics, Henning Karlsen. All right reserved
  
  Basic functionality of this library are based on the demo-code provided by
  ITead studio.
 
  You can find the latest version of the library at 
  http://www.RinkyDinkElectronics.com/
 
  This library is free software; you can redistribute it and/or
  modify it under the terms of the CC BY-NC-SA 3.0 license.
  Please see the included documents for further information.
 
  Commercial use of this library requires you to buy a license that
  will allow commercial use. This includes using the library,
  modified or not, as a tool to sell products.
 
  The license applies to all part of the library including the 
  examples and tools supplied with the library.
*/
 
#include "RLucas_TFT_Touch.h"
#include "RLucas_TFT_TouchCD.h"
 
void URTouch::touch_WriteData(byte data)
{
	byte temp;
 
	temp=data;
	cbi(P_CLK, B_CLK);
 
	for(byte count=0; count<8; count++)
	{
		if(temp & 0x80)
			sbi(P_DIN, B_DIN);
		else
			cbi(P_DIN, B_DIN);
		temp = temp << 1; 
		cbi(P_CLK, B_CLK);                
		sbi(P_CLK, B_CLK);
	}
}
 
word URTouch::touch_ReadData()
{
	word data = 0;
 
	for(byte count=0; count<12; count++)
	{
		data <<= 1;
		sbi(P_CLK, B_CLK);
		cbi(P_CLK, B_CLK);                
		if (rbi(P_DOUT, B_DOUT))
			data++;
	}
	return(data);
}
 
 
URTouch::URTouch(byte tclk, byte tcs, byte din, byte dout, byte irq)
{
	T_CLK	= tclk;
	T_CS	= tcs;
	T_DIN	= din;
	T_DOUT	= dout;
	T_IRQ	= irq;
}
 
void URTouch::InitTouch(byte orientation)
{
	orient					= orientation;
	_default_orientation	= CAL_S>>31;
	touch_x_left			= (CAL_X>>14) & 0x3FFF;
	touch_x_right			= CAL_X & 0x3FFF;
	touch_y_top				= (CAL_Y>>14) & 0x3FFF;
	touch_y_bottom			= CAL_Y & 0x3FFF;
	disp_x_size				= (CAL_S>>12) & 0x0FFF;
	disp_y_size				= CAL_S & 0x0FFF;
	prec					= 10;
 
	P_CLK	= portOutputRegister(digitalPinToPort(T_CLK));
	B_CLK	= digitalPinToBitMask(T_CLK);
	P_CS	= portOutputRegister(digitalPinToPort(T_CS));
	B_CS	= digitalPinToBitMask(T_CS);
	P_DIN	= portOutputRegister(digitalPinToPort(T_DIN));
	B_DIN	= digitalPinToBitMask(T_DIN);
	P_DOUT	= portInputRegister(digitalPinToPort(T_DOUT));
	B_DOUT	= digitalPinToBitMask(T_DOUT);
	P_IRQ	= portInputRegister(digitalPinToPort(T_IRQ));
	B_IRQ	= digitalPinToBitMask(T_IRQ);
 
	pinMode(T_CLK,  OUTPUT);
    pinMode(T_CS,   OUTPUT);
    pinMode(T_DIN,  OUTPUT);
    pinMode(T_DOUT, INPUT);
    pinMode(T_IRQ,  OUTPUT);
 
	sbi(P_CS, B_CS);
	sbi(P_CLK, B_CLK);
	sbi(P_DIN, B_DIN);
	sbi(P_IRQ, B_IRQ);
}
 
void URTouch::read()
{
	unsigned long tx=0, temp_x=0;
	unsigned long ty=0, temp_y=0;
	unsigned long minx=99999, maxx=0;
	unsigned long miny=99999, maxy=0;
	int datacount=0;
 
	cbi(P_CS, B_CS);                    
 
	pinMode(T_IRQ,  INPUT);
	for (int i=0; i<prec; i++)
	{
		if (!rbi(P_IRQ, B_IRQ))
		{
			touch_WriteData(0x90);        
			pulse_high(P_CLK, B_CLK);
			temp_x=touch_ReadData();
 
			if (!rbi(P_IRQ, B_IRQ))
			{
				touch_WriteData(0xD0);      
				pulse_high(P_CLK, B_CLK);
				temp_y=touch_ReadData();
 
				if ((temp_x>0) and (temp_x<4096) and (temp_y>0) and (temp_y<4096))
				{
					tx+=temp_x;
					ty+=temp_y;
					if (prec>5)
					{
						if (temp_x<minx)
							minx=temp_x;
						if (temp_x>maxx)
							maxx=temp_x;
						if (temp_y<miny)
							miny=temp_y;
						if (temp_y>maxy)
							maxy=temp_y;
					}
					datacount++;
				}
			}
		}
	}
	pinMode(T_IRQ,  OUTPUT);
 
	if (prec>5)
	{
		tx = tx-(minx+maxx);
		ty = ty-(miny+maxy);
		datacount -= 2;
	}
 
	sbi(P_CS, B_CS);                    
	if ((datacount==(prec-2)) or (datacount==PREC_LOW))
	{
		if (orient == _default_orientation)
		{
			TP_X=ty/datacount;
			TP_Y=tx/datacount;
		}
		else
		{
			TP_X=tx/datacount;
			TP_Y=ty/datacount;
		}
	}
	else
	{
		TP_X=-1;
		TP_Y=-1;
	}
}
 
bool URTouch::dataAvailable()
{
	bool avail;
	pinMode(T_IRQ,  INPUT);
	avail = !(rbi(P_IRQ, B_IRQ));
	pinMode(T_IRQ,  OUTPUT);
	return avail;
}
 
int16_t URTouch::getX()
{
	long c;
 
	if ((TP_X==-1) or (TP_Y==-1))
		return -1;
	if (orient == _default_orientation)
	{
		c = long(long(TP_X - touch_x_left) * (disp_x_size)) / long(touch_x_right - touch_x_left);
		if (c<0)
			c = 0;
		if (c>disp_x_size)
			c = disp_x_size;
	}
	else
	{
		if (_default_orientation == PORTRAIT)
			c = long(long(TP_X - touch_y_top) * (-disp_y_size)) / long(touch_y_bottom - touch_y_top) + long(disp_y_size);
		else
			c = long(long(TP_X - touch_y_top) * (disp_y_size)) / long(touch_y_bottom - touch_y_top);
		if (c<0)
			c = 0;
		if (c>disp_y_size)
			c = disp_y_size;
	}
	return c;
}
 
int16_t URTouch::getY()
{
	int c;
 
	if ((TP_X==-1) or (TP_Y==-1))
		return -1;
	if (orient == _default_orientation)
	{
		c = long(long(TP_Y - touch_y_top) * (disp_y_size)) / long(touch_y_bottom - touch_y_top);
		if (c<0)
			c = 0;
		if (c>disp_y_size)
			c = disp_y_size;
	}
	else
	{
		if (_default_orientation == PORTRAIT)
			c = long(long(TP_Y - touch_x_left) * (disp_x_size)) / long(touch_x_right - touch_x_left);
		else
			c = long(long(TP_Y - touch_x_left) * (-disp_x_size)) / long(touch_x_right - touch_x_left) + long(disp_x_size);
		if (c<0)
			c = 0;
		if (c>disp_x_size)
			c = disp_x_size;
	}
	return c;
}
 
void URTouch::setPrecision(byte precision)
{
	switch (precision)
	{
		case PREC_LOW:
			prec=1;		// DO NOT CHANGE!
			break;
		case PREC_MEDIUM:
			prec=12;	// Iterations + 2
			break;
		case PREC_HI:
			prec=27;	// Iterations + 2
			break;
		case PREC_EXTREME:
			prec=102;	// Iterations + 2
			break;
		default:
			prec=12;	// Iterations + 2
			break;
	}
}
 
void URTouch::calibrateRead()
{
	unsigned long tx=0;
	unsigned long ty=0;
 
	cbi(P_CS, B_CS);                    
 
	touch_WriteData(0x90);        
	pulse_high(P_CLK, B_CLK);
	tx=touch_ReadData();
 
	touch_WriteData(0xD0);      
	pulse_high(P_CLK, B_CLK);
	ty=touch_ReadData();
 
	sbi(P_CS, B_CS);                    
 
	TP_X=ty;
	TP_Y=tx;
}
Nouvelle version du fichier .h de la librairie :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
#define PORTRAIT			0
#define LANDSCAPE			1
 
#define PREC_LOW			1
#define PREC_MEDIUM			2
#define PREC_HI				3
#define PREC_EXTREME		4
 
class URTouch
{
	public:
		int	TP_X ,TP_Y;
 
		URTouch(byte tcs, byte irq);
 
		void	InitTouch(byte orientation = LANDSCAPE);
		void	read();
		bool	dataAvailable();
		int	getX();
		int	getY();
		void	setPrecision(byte precision);
 
		//void	calibrateRead();
 
    private:
		//byte	T_CLK, T_CS, T_DIN, T_DOUT, T_IRQ;
		byte	T_CS, T_IRQ;
		long	_default_orientation;
		byte	orient;
		byte	prec;
		byte	display_model;
		long	disp_x_size, disp_y_size, default_orientation;
		long	touch_x_left, touch_x_right, touch_y_top, touch_y_bottom;
 
		word	touch_ReadData(byte data);
};
Nouvelle version du fichier .cpp de la librairie :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
//https://forum.arduino.cc/index.php?topic=313633.0
 
#include "SPI.h"
#include "RLucas_TFT_Touch.h"
#include "RLucas_TFT_TouchCD.h"
 
URTouch::URTouch(byte tcs, byte irq)
{
    T_CS = tcs;
    T_IRQ = irq;
}
 
void URTouch::InitTouch(byte orientation)
{
	//On ne communique pas avec l'afficheur à ce stade
	orient					= orientation;
	_default_orientation	= CAL_S>>31;
	touch_x_left			= (CAL_X>>14) & 0x3FFF;
	touch_x_right			= CAL_X & 0x3FFF;
	touch_y_top				= (CAL_Y>>14) & 0x3FFF;
	touch_y_bottom			= CAL_Y & 0x3FFF;
	disp_x_size				= (CAL_S>>12) & 0x0FFF;
	disp_y_size				= CAL_S & 0x0FFF;
	prec					= 10;
 
    //pinMode(T_IRQ, OUTPUT);
    //pinMode(T_CS, OUTPUT);
	digitalWrite(T_CS,  HIGH);
 
/*
	SPI.begin();
	SPI.setDataMode(SPI_MODE3);
    SPI.setClockDivider(SPI_CLOCK_DIV4);
    SPI.setBitOrder(MSBFIRST);
*/
}
 
void URTouch::setPrecision(byte precision)
{
	//On ne communique pas avec l'afficheur à ce stade
	switch (precision)
	{
		case PREC_LOW:
			prec=1;		// DO NOT CHANGE!
			break;
		case PREC_MEDIUM:
			prec=12;	// Iterations + 2
			break;
		case PREC_HI:
			prec=27;	// Iterations + 2
			break;
		case PREC_EXTREME:
			prec=102;	// Iterations + 2
			break;
		default:
			prec=12;	// Iterations + 2
			break;
	}
}
 
bool URTouch::dataAvailable()
{
	//On ne communique pas avec l'afficheur à ce stade, on regarde juste l'état de la broche :
	bool avail;
	//pinMode(T_IRQ,  INPUT);
	avail = !digitalRead(T_IRQ);
	//pinMode(T_IRQ,  OUTPUT);
	return avail;
}
 
void URTouch::read()
{
	unsigned long tx=0, temp_x=0;
	unsigned long ty=0, temp_y=0;
	int datacount=0;
 
	//With most SPI devices
	//after SPI.beginTransaction() you will write the slave select pin LOW
	//call SPI.transfer() any number of times to transfer data
	//then write the SS pin HIGH
	//and finally call SPI.endTransaction().
 
	//SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE3));
	SPI.beginTransaction(SPISettings(400000, MSBFIRST, SPI_MODE3)); // Test avec une vitesse SPI plus faible
	digitalWrite(T_CS,LOW);
 
	for (int i=0; i<prec; i++)
	{
        //added param command - RB 6/4/15
		temp_x = touch_ReadData(0x90);
		temp_y = touch_ReadData(0xD0);
 
		if (!((temp_x>max(touch_x_left, touch_x_right)) or (temp_x==0) or (temp_y>max(touch_y_top, touch_y_bottom)) or (temp_y==0)))
		{
			ty+=temp_x;
			tx+=temp_y;
			datacount++;
		}
	}
 
	digitalWrite(T_CS,HIGH);
	SPI.endTransaction();
	if (datacount>0)
	{
		if (orient == _default_orientation)
		{
			TP_X=tx/datacount;
			TP_Y=ty/datacount;
		}
		else
		{
			TP_X=ty/datacount;
			TP_Y=tx/datacount;
		}
	}
	else
	{
		TP_X=-1;
		TP_Y=-1;
	}
}
//combined the write data method into the read seeing as HW SPI does both at the same time - RB 06/04/15
word URTouch::touch_ReadData(byte command)
{
	//first send the command, this will not return anything useful so disregard the return byte
	SPI.transfer(command);
 
	//next we need to send 12 bits of nothing to get the 12 bits we need back
	//we can only send in batches of 8, ie 1 byte so do this twice
	byte f1 = SPI.transfer(0x00);
	byte f2 = SPI.transfer(0x00);
 
	//combine the 16 bits into a word
	word w = word(f1, f2);
 
	//the word is organised with MSB leftmost, shift right by 3 to make 12 bits
	w = w >> 3;
 
	//and return the result
	return w;
}
 
int URTouch::getX()
{
	long c;
 
	if (orient == _default_orientation)
	{
		c = long(long(TP_X - touch_x_left) * (disp_x_size)) / long(touch_x_right - touch_x_left);
		if (c<0)
			c = 0;
		if (c>disp_x_size)
			c = disp_x_size;
	} else {
		if (_default_orientation == PORTRAIT)
			c = long(long(TP_X - touch_y_top) * (-disp_y_size)) / long(touch_y_bottom - touch_y_top) + long(disp_y_size);
		else
			c = long(long(TP_X - touch_y_top) * (disp_y_size)) / long(touch_y_bottom - touch_y_top);
		if (c<0)
			c = 0;
		if (c>disp_y_size)
			c = disp_y_size;
	}
 
	return c;
}
 
int URTouch::getY()
{
	int c;
 
	if (orient == _default_orientation)
	{
		c = long(long(TP_Y - touch_y_top) * (disp_y_size)) / long(touch_y_bottom - touch_y_top);
		if (c<0)
			c = 0;
		if (c>disp_y_size)
			c = disp_y_size;
	} else {
		if (_default_orientation == PORTRAIT)
			c = long(long(TP_Y - touch_x_left) * (disp_x_size)) / long(touch_x_right - touch_x_left);
		else
			c = long(long(TP_Y - touch_x_left) * (-disp_x_size)) / long(touch_x_right - touch_x_left) + long(disp_x_size);
		if (c<0)
			c = 0;
		if (c>disp_x_size)
			c = disp_x_size;
	}
	return c;
}
 
/*
void URTouch::calibrateRead()
{
	unsigned long tx=0;
	unsigned long ty=0;
 
	SPI.begin();
	digitalWrite(T_CS,LOW);
 
	tx=touch_ReadData(0x90);
    ty=touch_ReadData(0xD0);
 
	digitalWrite(T_CS,HIGH);
	SPI.end();
 
	TP_X=ty;
	TP_Y=tx;
}
*/
A noter : le fichier RLucas_TFT_TouchCD.h est inchangé, ce sont les données de calibration.

Voici mon sketch :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
//Ethernet plus rapide ?
//https://forum.arduino.cc/index.php?topic=217183.0
 
#include <SPI.h>
 
// DALLE TACTILE ************************************************************************************************************************************************
// Calibration à faire avec 003_TFT_Touch_Calibrate_OK
#include "RLucas_TFT_Touch.h"
#define t_IRQ 5
#define t_MISO 7 // ROUGE (TFT OUT) // La broche 4 est utilisée pour le lecteur SD de l'ethernet Shield
#define t_MOSI 3 // VERT (TFT IN)
#define t_CS 2  // JAUNE
#define t_SCK 1 // BLEU
//URTouch ts(t_SCK, t_CS, t_MOSI, t_MISO, t_IRQ);
URTouch ts(t_CS, t_IRQ);
 
// ECRAN TFT ****************************************************************************************************************************************************
#include "RLucas_TFT_GFX.h"
#include "RLucas_TFT_ILI9341_config.h" // C'est dans le fichier PDQ_ILI9341_config.h qu'on définit les broches CS, DC et RST :
//#define ILI9341_CS_PIN    0   // <= /CS pin (chip-select, LOW to get attention of ILI9341, HIGH and it ignores SPI bus)
//#define ILI9341_DC_PIN    9   // <= DC pin (1=data or 0=command indicator line) also called RS
//#define ILI9341_RST_PIN   8   // <= RST pin (optional)
//#define  ILI9341_SAVE_SPCR 0     // <= 0/1 with 1 to save/restore AVR SPI control register (to "play nice" when other SPI use) => prend plus de code et non nécessaire !
#include "RLucas_TFT_ILI9341.h"      // PDQ: Hardware-specific driver library
PDQ_ILI9341 tft;      
#define TFT_PWM_LED 6 // Un transistor PNP permet de piloter le rétroéclairage 
 
// ETHERNET *****************************************************************************************************************************************************
#include "RLucas_Ethernet.h"
// Ethernet Shield 2 : communicates with both the W5500 and SD card using the SPI bus (through the ICSP header).
// This is on digital pins 10, 11, 12, and 13 on the Uno and pins 50, 51, and 52 on the Mega.
// On both boards, pin 10 is used to select the W5500 and pin 4 for the SD card. These pins cannot be used for general I/O.
// On the Mega, the hardware SS pin, 53, is not used to select either the W5500 or the SD card, but it must be kept as an output or the SPI interface won't work.
byte mac[] = {
  0xA8, 0x61, 0x0A, 0xAE, 0x75, 0xCA //Voir étiquette collée sous le Shield
};
IPAddress ip(192, 168, 123, 177); //Choisir une IP fixe compatible avec le réseau local ou bien utiliser DHCP
//IPAddress myDns(212, 27, 40, 240);
//IPAddress myDns(192, 168, 123, 254); //DNS ou adresse du routeur  - Indispensable si IP Fixe (sans DHCP) et si on souhaite aller sur INTERNET (mais pas en local)
//IPAddress gateway(192, 168, 123, 254); //Adresse du routeur - Indispensable si IP Fixe (sans DHCP) et si on souhaite aller sur INTERNET (mais pas en local)
EthernetClient client;
byte serverIP[] = { 192, 168, 123, 32 }; // Adresse IP du PC Fixe
#define NetworkTimeout 2000
 
// To open a port in the Windows 7 Firewall
// On the Start menu, click Control Panel
// Click on the System and Security category, then Windows Firewall. If you are not viewing by category, you can simply click on the Window Firewall item.
// Click on the Advanced Settings link on the left hand side. This will open the Windows Firewall with Advanced Security Management Console application.
// Click on Inbound Rules on the left hand menu. Under the Actions on the right hand side, click on New Rule. This opens the New Inbound Rule Wizard.
// Select the Port option and click Next.
// Select TCP and Specific local ports (80), then enter a comma-separated list of port numbers you want to open and click Next.
// Select Allow the connection and click Next.
// Check the boxes next to the desired network types and click Next.
// Enter a name for your rule - and optionally a description - and click Finish.
// Your inbound rule should now be displayed on the Inbound Rules list. To remove this rule, simply delete it from the list when you are done.
 
// VARIABLES GLOBALES *******************************************************************************************************************************************
// Buffer qui contient les requêtes et les réponses HTTP :
#define Buffer_HTTP_Len 512
char Buffer_HTTP[Buffer_HTTP_Len];
int Buffer_HTTP_Stop; // Les données à traiter sont les octers de Buffer_HTTP de [0] à [Buffer_HTTP_Stop-1]
int Buffi;
 
// Variables "RAM" pouvant être écrites par le serveur et conservées :
#define Buffer_RAM_Len 512
char Buffer_RAM[Buffer_RAM_Len];
int R1;
int R2;
int W1;
int H1;
int W2;
int H2;
unsigned int Couleur[14];
int Palette; // Palette peut valoir 0 ou 7; la couleur à utiliser est définie par Couleur[index+Palette] avec index=0...6
 
//Variables globales :
int Status;
int Touch_X;
int Touch_Y;
unsigned long debut;
unsigned long duree;
unsigned long duree2;
int X1;
int Y1;
int X2;
int Y2;
int X3;
int Y3;
#define LIRE_X1_Y1 1
#define LIRE_X2_Y2 2
#define LIRE_X3_Y3 3
#define LIRE_W1_H1 4
#define LIRE_W2_H2 5
uint8_t C1R;
uint8_t C1G;
uint8_t C1B;
uint8_t C2R;
uint8_t C2G;
uint8_t C2B;
int L;
 
#define LireEntreeAnalogique 1
#define LireEntreeNumerique 2
#define LireEntreeLumiere 3
const int MaxReadedPin = 10;
byte ReadedPin[MaxReadedPin];
int ReadedPinValue[MaxReadedPin];
int ReadedPinIndex;
 
#define PING_SERVEUR A5
boolean pinPingServeur;
 
#define AMBIANT_LIGHT A4
 
/*
#define AfficherBmpSansBG 1
#define AfficherBmpAvecBG 2
#define AfficherBmpBicolor 3
*/
 
//char Buffer[20];
 
 
// SETUP ********************************************************************************************************************************************************
void setup() {
  Ajuster_Lumiere();
  //duree2=millis();
 
  tft.begin();
  tft.setRotation(0);
 
  ts.InitTouch(PORTRAIT);
  ts.setPrecision(PREC_EXTREME);
/*
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
  tft.setTextSize(1);
*/
  // You can use Ethernet.init(CSpin) to configure the CS pin
  //Ethernet.begin(mac, ip, myDns, gateway); 
  Ethernet.begin(mac, ip);
  pinPingServeur = digitalRead(PING_SERVEUR);
 
  Status=0; // Démarrage
  Network_Contacter_Serveur();
}
 
// LOOP *********************************************************************************************************************************************************
void loop() {
  // Gestion du rétroéclairage :
  Ajuster_Lumiere();
  //duree2=millis();
  // On demande à l'écran tactile s'il y a eu un appui :
  if (ts.dataAvailable()) {
    ts.read();
    Touch_X = ts.getX();
    Touch_Y = ts.getY();
    if ((Touch_X != -1) && (Touch_Y != -1)) {
      //analogWrite(TFT_PWM_LED,128);// Juste pour indiquer la détection d'une touche
      Network_Contacter_Serveur();
    }
  }
  // On surveille la broche permettant au serveur de solliciter une requête :
  if (pinPingServeur != digitalRead(PING_SERVEUR)) {
    pinPingServeur = !pinPingServeur;
    Status = 2; //Requête à la demande du serveur
    Network_Contacter_Serveur();
  }
}
 
void Ajuster_Lumiere() {
  analogWrite(TFT_PWM_LED, 205 - min(analogRead(AMBIANT_LIGHT) / 3, 205));
}
 
// REQUETTE *****************************************************************************************************************************************************
 
void Network_Contacter_Serveur() {
  do {
    duree2=millis();
    Network_Construire_Requete_Traiter_Reponse();
  } while(Status > 2); // Fonction Force Another Request !
}
 
int Network_Envoyer_Requete_Pretraiter_Reponse() {
  int nb;
  char c;
  int i;
  //int j;
  //int nb_deja_lu;
  int RAM_pos;
  byte RAM_len;
  unsigned int longueur;
  byte crc;
  int err_RAM_Ecrite;
 
  duree=millis();
  // Connection au serveur web :
  // client.stop(); // L'arrêt du client prend beaucoup de temps, à faire après
  if (client.connect(serverIP, 80)) {
    client.print(Buffer_HTTP);
 
    //Attente de la réponse du serveur
    debut = millis();
    nb=0;
    while(nb==0){ 
      nb = client.available();
      if (millis()-debut>NetworkTimeout) {break;}
    }
 
    //Lecture de la réponse du serveur :
    if (nb==0) {
      return 1; // ERREUR : Le serveur met trop de temps à répondre
    } else {
      //On élimine l'entête, en cherchant le caractère '<' qui marque le début des données utiles :
      do {
        if (nb==0){
          return 3; // ERREUR : Le début des données n'a pas été trouvé
        }
        c=client.read();
        nb--;
      } while(c!='<');
 
      longueur = nb;
      crc = 0;
 
      if (nb==0){
        // Le serveur ne donne aucune instruction :
        Buffer_HTTP_Stop=0;
    return 9; // ERREUR : Manque Longueur + CRC
      }else{
        // Le serveur donne une ou plusieurs instructions :
        c=client.read();
        crc^=c;
        nb--;
 
        if (c==1) { // Network Resend data again
          // Le serveur demande à renvoyer les données, parce qu'il a mal reçu la requête :
          return 8; // ERREUR : Requête à recommencer
        }
 
        err_RAM_Ecrite = 0; // IMPORTANT : il peut se produire une erreur, alors qu'on a déjà écrit dans Buffer_RAM. Si oui le serveur devra en tenir compte lors du traitement de l'erreur.
 
        while(c==8) {
          // Ecriture dans le RAM buffer - Ces instructions d'écriture dans le RAM buffer ne peuvent être que les premières
          // ce qui permet d'éviter de stocker bêtement ces données en double dans le Buffer HTTP :
          nb-=2;
          if (nb<0){
            return 4 + err_RAM_Ecrite; // ERREUR : Données manquantes 
          }
          c=client.read();
          crc^=c;
          RAM_pos=(byte)c; //client.read();
          if (RAM_pos==255) {
            c=client.read();
            crc^=c;
            RAM_pos+=(byte)c; //client.read();
            nb--;
          }
          c=client.read();
          crc^=c;
          RAM_len=(byte)c; //client.read();
          nb-=RAM_len;
          if (nb<0){
            return 5 + err_RAM_Ecrite; // ERREUR : Données manquantes 
          }
          if (RAM_pos+RAM_len>=Buffer_RAM_Len){
            return 6 + err_RAM_Ecrite; // ERREUR : La position et la longeur d'écriture en RAM dépassent la limite
          }
          err_RAM_Ecrite = 32; // IMPORTANT : il peut se produire une erreur, alors qu'on a déjà écrit dans Buffer_RAM. Si oui le serveur devra en tenir compte lors du traitement de l'erreur.
          for (i=0;i<RAM_len;i++) {
            c=client.read(); // UTILISER PLUTOT : int EthernetClient::read(uint8_t *buf, size_t size) ? puis calculer le CRC ensuite ?
            crc^=c;
            Buffer_RAM[i+RAM_pos]=c; //client.read();
          }
          if (nb==0){
            // Le serveur ne donne aucune autre instruction :
            Buffer_HTTP_Stop=0;
            return 9 + err_RAM_Ecrite; // ERREUR : Manque Longueur + CRC
          }else{
            c=client.read();
            crc^=c;
            nb--;
          }
        }
 
        // Quand on arrive ici, le caractère 'c' qui a été lu auparavent est le premier caractère des instructions :
        Buffer_HTTP[0]=c;
        // Il reste 'nb' caractères à lire :
        if (nb>Buffer_HTTP_Len-2) {
          return 7 + err_RAM_Ecrite; // ERREUR : Trop de données envoyées par le serveur
        } 
        for (i=1;i<nb;i++) { //i<nb au lieu de i<=nb car le CRC ne doit pas être calculé sur lui-même
          c=client.read(); // UTILISER PLUTOT : int EthernetClient::read(uint8_t *buf, size_t size) ? puis calculer le CRC ensuite ?
          crc^=c;
          Buffer_HTTP[i]=c; //client.read();
        }
        c=client.read();
        Buffer_HTTP[i]=c; //=client.read();
        Buffer_HTTP_Stop=i+1;
      }
 
      // Il faut vérifier la longueur et le CRC :
      if (Buffer_HTTP_Stop<3) {
        return 9 + err_RAM_Ecrite; // ERREUR : Manque Longueur + CRC
      }
      Buffi=Buffer_HTTP_Stop-4; // Voir code de LireUInt16()
      if (longueur!=LireUInt16()) {
        return 10 + err_RAM_Ecrite; // ERREUR : Longueur incorrecte
      }
      if (crc!=(byte)Buffer_HTTP[Buffer_HTTP_Stop-1]) {
        return 11 + err_RAM_Ecrite; // ERREUR : CRC incorrect
      }
/*
      tft.fillScreen(0);
      tft.setCursor(0, 0);
      tft.print("L=");   //263 OK vu avec Wireshark
      tft.print(longueur);
      tft.print(" CRC="); //87 OK !
      tft.print(crc);
      tft.print(" nb=");  //200
      tft.print(nb);
      tft.print(" BHS="); //201
      tft.print(Buffer_HTTP_Stop);
      tft.print(" LD=");  //263 OK !
      Buffi=Buffer_HTTP_Stop-4;
      tft.print(LireUInt16());
      tft.print(" C=");   //87 OK !
      tft.println((byte)Buffer_HTTP[Buffer_HTTP_Stop-1]);
      tft.println();
      j=0;
      for (i=0;i<Buffer_HTTP_Stop;i++) {
        snprintf_P(Buffer, sizeof(Buffer), PSTR("%02x"), (byte)Buffer_HTTP[i]);
        tft.print(Buffer);
        tft.print(F(" "));
        j++;
        if (j>9) {
          j=0;
          tft.println();
        }
      }
      return 11;
*/
      // IMPORTANT : la longueur et le CRC ne doivent pas être exécutés !!!
      Buffer_HTTP_Stop-=3;
 
      return 0; // SUCCES
    }
  } else {
      return 2; // ERREUR : Pas de connection
  }
}
 
void Network_Construire_Requete_Traiter_Reponse() {
  int err_code;
  int i;
  int j;
  byte instr;
  int s;
  byte coul_index;
  int pos;
  int pin;
  int value;
  int valueoff;
  int w;
  int crc;
  unsigned int couleur1;
  unsigned int couleur2;
 
  //uint8_t *pointeur;
/*
  int nb_ai;
  byte ai[50];
  int ai_ind[50];
  nb_ai=0;
*/
  err_code=0;
  do {
    // On construit la requête au serveur ici :
    //snprintf_P(Buffer_HTTP, sizeof(Buffer_HTTP), PSTR("GET /?E=%d&S=%d&X=%d&Y=%d HTTP/1.1\r\nHost:\r\nConnection: close\r\n\r\n"), err_code, Status, Touch_X, Touch_Y);
 
    /*
    strncpy_P(Buffer_HTTP, sizeof(Buffer_HTTP), PSTR("GET /?"));
    i=snprintf_P(Buffer_HTTP+6, sizeof(Buffer_HTTP)-6, PSTR("E=%d&S=%d&X=%d&Y=%d"), err_code, Status, Touch_X, Touch_Y);
    strncpy_P(Buffer_HTTP+i+6, sizeof(Buffer_HTTP), PSTR(" HTTP/1.1\r\nHost:\r\nConnection: close\r\n\r\n"));
    */
    /*
    strcpy_P(Buffer_HTTP, PSTR("GET /?"));
    i=6;
    i=sprintf_P(Buffer_HTTP+i, PSTR("E=%d&S=%d&X=%d&Y=%d"), err_code, Status, Touch_X, Touch_Y);
    */
    crc = err_code ^ Status ^ Touch_X ^ Touch_Y;
    i=sprintf_P(Buffer_HTTP, PSTR("GET /?E=%d&S=%d&X=%d&Y=%d"), err_code, Status, Touch_X, Touch_Y);
     if (Status==4) {
      for (j=0;j<ReadedPinIndex;j++) {
        i+=sprintf_P(Buffer_HTTP+i, PSTR("&I%d=%d"), ReadedPin[j], ReadedPinValue[j]);
        crc^=ReadedPinValue[j];
      }
    }
    i+=sprintf_P(Buffer_HTTP+i, PSTR("&C=%d"), crc);
    strcpy_P(Buffer_HTTP+i, PSTR(" HTTP/1.1\r\nHost:\r\nConnection: close\r\n\r\n"));
 
    // Le serveur connait :
    //
    //- Status
    //   0 : Le client démarre les variables et Buffer_RAM sont vides
    //   1 : Fonctionnement normal
    //   2 : Le client fait une requête à la demande du serveur (fil "interruption")
    //   3 : Le client dit au serveur qu'il est prêt a recevoir la suite de la réponse que le serveur avait demandé
    //   4 : Le client envoit la lecture des broches d'entrées que le serveur a demandé
    //
    //- err_code : le client a rencontré une erreur et demande au serveur une nouvelle requête
    //   err_code                  Le serveur a bien eu la requête précédente ?
    //   0 : SUCCES                OUI => traiter la requête normalement
    //   1 : Timeout               NON => traiter la requête normalement
    //   2 : Pas de connection     NON => traiter la requête normalement
    //   3 : Début non trouvé      OUI => juste renvoyer la réponse précédente
    //   4 : Données manquantes    OUI => juste renvoyer la réponse précédente
    //   5 : Données manquantes    OUI => juste renvoyer la réponse précédente
    //   6 : RAM overflow          OUI => juste renvoyer la réponse précédente
    //   7 : Trop de données       OUI => juste renvoyer la réponse précédente
    //   8 : Requête à recommencer OUI mais le serveur a rencontré une erreur et redemande la requete au client => traiter la requête normalement
    //   9 : CRC manquant          OUI => juste renvoyer la réponse précédente
    //   10: Longueur incorrecte   OUI => juste renvoyer la réponse précédente
    //   11: CRC incorrect         OUI => juste renvoyer la réponse précédente
    //
    //   IMPORTANT : err_code est augmenté de 32 si Buffer_RAM a été possiblement corrompu par des données incorrectes.
    //               dans ce cas de figure le serveur devra renvoyer les données pour remplir Buffer_RAM avec des données sûres.
    //
    //   "traiter la requête normalement" :
    //   - Si Status = 0 => le serveur doit envoyer les données d'initialisation
    //   - Si Status = 1 => le serveur doit executer l'action correspondant à la frappe sur le pavé tactile X et Y
    //   - Si Status = 2 => le serveur doit envoyer les données qu'il souhaite (requête client faite à la demande du serveur)
    //   - Si Status = 3 => le serveur doit envoyer la suite des données si il y a une suite disponible 
    //   - Si Status = 4 => le serveur doit lire les données lues, et envoyer la suite des données si il y a une suite disponible 
 
    err_code = Network_Envoyer_Requete_Pretraiter_Reponse();
    duree = millis()-duree;
 
    tft.tftSpiBegin();
    if (err_code==0) {
      // On traite la réponse ici :
      // Les instructions et les données à traiter sont comprises entre Buffer_HTTP[0] et Buffer_HTTP[Buffer_HTTP_Stop-1]
 
      Status=1; // On réinitialise le statut à la valeur "normale"
      ReadedPinIndex = 0;
      Buffi=-1;
 
      while(Buffi<Buffer_HTTP_Stop-1) {
        instr = LireUByte();
        if (instr>31) {
          // Il faut récupérer l'index de la couleur et remettre le numéro de l'instruction de base :
          coul_index = (instr - 32) % 7;
          instr -= coul_index;
          coul_index += Palette;
          if (instr>52 && instr<228) {
            LireXY(LIRE_X1_Y1); // Eviter de copier cette instruction de multiples fois (cases vertes dans le tableau Excel)
          }
        }else{
          if (instr>15 && instr<20) {
            // Dégradés
            LireXY(LIRE_X1_Y1); // Eviter de copier cette instruction de multiples fois (cases vertes dans le tableau Excel)
            LireXY(LIRE_X2_Y2); // Eviter de copier cette instruction de multiples fois (cases bleues dans le tableau Excel)
            if (instr>17) {
              couleur1 = LireUInt16();                      
              couleur2 = LireUInt16();
              instr-=2;
            }else{
              couleur1 = Couleur[LireUInt8()];                      
              couleur2 = Couleur[LireUInt8()]; 
            }
            C1R = ((couleur1 >> 11) & 0x1F);
            C1G = ((couleur1 >> 5) & 0x3F);
            C1B = (couleur1 & 0x1F);
            C2R = ((couleur2 >> 11) & 0x1F);
            C2G = ((couleur2 >> 5) & 0x3F);
            C2B = (couleur2 & 0x1F);
          }else{
            if (instr>20 && instr<25) {
              // Il faut récupérer la taille du texte et remettre le numéro de l'instruction de base :
              s = instr-20;    
              instr = 21;
            }
          }
        }
/*
        ai[nb_ai]=instr;
        ai_ind[nb_ai]=Buffi;
        nb_ai++;
*/
        switch (instr) {
          case 0: // 
            // A FAIRE
            break;
          // case 1: Network Resend data => Traité dans la procédure Network_Faire_Requete();
          case 2: // Network Force other request
            if (Status<3) {Status = 3;} // Force other request (demande la suite) - Il faut laisser le Status à 4 s'il y est déjà
            break;
          case 3: // Write pin
            pin = LireUInt8();
            value = LireUInt8();
            //pinMode(pin, OUTPUT); //déjà dans analogWrite
            analogWrite(pin,value);
            break;
          case 4: // Write pin pulse
            pin = LireUInt8();
            w = LireUInt9();
            value = LireUInt8();
            valueoff = LireUInt8();
            //pinMode(pin, OUTPUT); //déjà dans analogWrite
            analogWrite(pin,value);
            delay(w);
            analogWrite(pin,valueoff);
            break;
          case 5: // Read digital pin
            LireEntree(LireEntreeNumerique);
            break;
          case 6: // Read analog pin
            LireEntree(LireEntreeAnalogique);
            break;
          case 7: // Read Ambiant light
            LireEntree(LireEntreeLumiere);
            break;
          case 9: // Set R1
            R1 = LireUInt9();
            break;
          case 10: // Set R2
            R2 = LireUInt9();
            break;
          case 11: // Set W1 H1
            LireXY(LIRE_W1_H1);
            break;
          case 12: // Set W2 H2
            LireXY(LIRE_W2_H2);
            break;
          case 13: // Set color
            i = LireUInt8();
            Couleur[i] = LireUInt16();
            break;
          case 14: // Set color index 0...6
            Palette=0;
            break;
          case 15: // Set color index 7...13
            Palette=7;
            break;
 
          case 16: // TFT Fill Rect Colormorph H
            L = X2-1;
            for (i=0;i<X2;i++) {
              tft.drawFastVLine(i+X1, Y1, Y2, CouleurDegrade(i));
            }
            break;
          case 17: // TFT Fill Rect Colormorph V
            L = Y2-1;
            for (i=0;i<Y2;i++) {
              tft.drawFastHLine(X1, i+Y1, X2, CouleurDegrade(i));
            }
            break;
 
          case 20: // TFT Set text cursor 
            LireXY(LIRE_X1_Y1);
            tft.setCursor(X1, Y1);
            break;
          case 21: // TFT Set text size 
            tft.setTextSize(s);
            break;
          case 25: // TFT Set text wrap off 
            tft.setTextWrap(false);
            break;
          case 26: // TFT Set text wrap on 
            tft.setTextWrap(true);
            break;
          case 27: // TFT Set text color
              tft.setTextColor(Couleur[LireUInt8()]);
            break;
          case 28: // TFT Set text color & BG color
              i=LireUInt8();
              tft.setTextColor(Couleur[i],Couleur[LireUInt8()]);
            break;
          case 29: // TFT Print @RAM
            pos=LireUInt9();
            tft.print((char*)(Buffer_RAM + pos));
            break;
          case 30: // TFT Print
            PrintString();
            break;
          case 31: // TFT Print char
            Buffi++;
            tft.print(Buffer_HTTP[Buffi]);
            break;
 
          case 46: // TFT Fill Screen
            tft.fillScreen(Couleur[coul_index]);
            break;
 
          case 32: // TFT Draw Rect Button
            w = PrintString();
            // A FAIRE
            break;
          case 39: // TFT Draw Circle Button
            w = PrintString();
            // A FAIRE
            break;
 
          case 53: // TFT Draw Line
            LireXY(LIRE_X2_Y2);
            tft.drawLine(X1, Y1, X2, Y2, Couleur[coul_index]);
            break;
          case 60: // TFT Draw H Line
            tft.drawFastHLine(X1, Y1, LireUInt9(), Couleur[coul_index]);
            break;
          case 67: // TFT Draw V Line
            tft.drawFastVLine(X1, Y1, LireUInt9(), Couleur[coul_index]);
            break;
 
          case 74: // TFT Draw Rect
            LireXY(LIRE_X2_Y2);
            tft.drawRect(X1, Y1, X2, Y2, Couleur[coul_index]);
            break;
          case 88: // TFT Draw Rect Size1
            tft.drawRect(X1, Y1, W1, H1, Couleur[coul_index]);
            break;
          case 102: // TFT Draw Rect Size2
            tft.drawRect(X1, Y1, W2, H2, Couleur[coul_index]);
            break;
 
          case 81: // TFT Draw Round Rect
            LireXY(LIRE_X2_Y2);
            tft.drawRoundRect(X1, Y1, X2, Y2, LireUInt9(), Couleur[coul_index]);
            break;
          case 95: // TFT Draw Round Rect Size1 R1
            tft.drawRoundRect(X1, Y1, W1, H1, R1, Couleur[coul_index]);
            break;
          case 109: // TFT Draw Round Rect Size2 R2
            tft.drawRoundRect(X1, Y1, W2, H2, R2, Couleur[coul_index]);
            break;
 
          case 116: // TFT Draw Circle
            tft.drawCircle(X1, Y1, LireUInt9(), Couleur[coul_index]);
            break;
          case 123: // TFT Draw Circle R1
            tft.drawCircle(X1, Y1, R1, Couleur[coul_index]);
            break;
          case 130: // TFT Draw Circle R2
            tft.drawCircle(X1, Y1, R2, Couleur[coul_index]);
            break;
 
          case 137: // TFT Draw Triangle
            LireXY(LIRE_X2_Y2);
            LireXY(LIRE_X3_Y3);
            tft.drawTriangle(X1, Y1, X2, Y2, X3, Y3, Couleur[coul_index]);
            break;
          case 144: // TFT Draw Triangle
            X2 = X1 + W1;
            Y2 = Y1 + H1;
            X3 = X1 + W2;
            Y3 = Y1 + H2;
            tft.drawTriangle(X1, Y1, X2, Y2, X3, Y3, Couleur[coul_index]);
            break;
 
          case 151: // TFT Fill Rect
            LireXY(LIRE_X2_Y2);
            tft.fillRect(X1, Y1, X2, Y2, Couleur[coul_index]);
            break;
          case 165: // TFT Fill Rect Size1
            tft.fillRect(X1, Y1, W1, H1, Couleur[coul_index]);
            break;
          case 179: // TFT Fill Rect Size2
            tft.fillRect(X1, Y1, W2, H2, Couleur[coul_index]);
            break;
 
          case 158: // TFT Fill Round Rect
            LireXY(LIRE_X2_Y2);
            tft.fillRoundRect(X1, Y1, X2, Y2, LireUInt9(), Couleur[coul_index]);
            break;
          case 172: // TFT Fill Round Rect Size1 R1
            tft.fillRoundRect(X1, Y1, W1, H1, R1, Couleur[coul_index]);
            break;
          case 186: // TFT Fill Round Rect Size2 R2
            tft.fillRoundRect(X1, Y1, W2, H2, R2, Couleur[coul_index]);
            break;
 
          case 193: // TFT Fill Circle
            tft.fillCircle(X1, Y1, LireUInt9(), Couleur[coul_index]);
            break;
          case 200: // TFT Fill Circle R1
            tft.fillCircle(X1, Y1, R1, Couleur[coul_index]);
            break;
          case 207: // TFT Fill Circle R2
            tft.fillCircle(X1, Y1, R2, Couleur[coul_index]);
            break;
 
          case 214: // TFT Fill Triangle
            LireXY(LIRE_X2_Y2);
            LireXY(LIRE_X3_Y3);
            tft.fillTriangle(X1, Y1, X2, Y2, X3, Y3, Couleur[coul_index]);
            break;
          case 221: // TFT Fill Triangle
            X2 = X1 + W1;
            Y2 = Y1 + H1;
            X3 = X1 + W2;
            Y3 = Y1 + H2;
            tft.fillTriangle(X1, Y1, X2, Y2, X3, Y3, Couleur[coul_index]);
            break;
 
          case 228: // 
 
            break;
          case 235: // TFT Draw Bitmap RAM
            i = LireUInt9(); // La position du bitmap dans Buffer_RAM est dans Buffer_HTTP
            LireXY(LIRE_X1_Y1); // X1 et Y1 sont dans Buffer_HTTP
            //tft.drawBitmap(X1, Y1, (byte*)(Buffer_RAM + i + 2), Buffer_RAM[i], Buffer_RAM[i+1], Couleur[coul_index], 0, false, LireUInt8());
            tft.drawBitmap(X1, Y1, (byte*)(Buffer_RAM + i + 2), Buffer_RAM[i], Buffer_RAM[i+1], Couleur[coul_index], 0, LireUInt8());
            break;
          case 242: // TFT Draw Bitmap RAM + Bicolor
            i = LireUInt9(); // La position du bitmap dans Buffer_RAM est dans Buffer_HTTP
            LireXY(LIRE_X1_Y1); // X1 et Y1 sont dans Buffer_HTTP
            j = LireUInt8();
            tft.drawBitmap(X1, Y1, (byte*)(Buffer_RAM + i + 2), Buffer_RAM[i], Buffer_RAM[i+1], Couleur[coul_index], Couleur[j], LireUInt8());
            break;
          case 249: // TFT Draw Bitmap RAM + BG
            i = LireUInt9(); // La position du bitmap dans Buffer_RAM est dans Buffer_HTTP
            LireXY(LIRE_X1_Y1); // X1 et Y1 sont dans Buffer_HTTP
            tft.drawBitmap(X1, Y1, (byte*)(Buffer_RAM + i + 2), Buffer_RAM[i], Buffer_RAM[i+1], Couleur[coul_index], Couleur[Palette], LireUInt8());
            break;
 
          default:
            break;
        }
 
      } 
 
 
      // Affichage de debug : -----------------------------------------------------------------------------
      //tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
      tft.setCursor(0, 0);
      tft.print(duree); // Temps pris pour envoyer la requête au serveur et recevoir la réponse
      tft.print(F("ms "));
      tft.print(millis()-duree2-duree);  // Temps pris pour gérer l'appui sur l'écran tactile et l'affichage
      tft.print(F("ms "));
      tft.println(Buffer_HTTP_Stop);
/*
      tft.println();
      for (i=0;i<8;i++){
        snprintf_P(Buffer, sizeof(Buffer), PSTR("%d %04x"), i, Couleur[i]);
        tft.println(Buffer);
      }
      tft.println();
 
      j=0;
      for (i=0;i<Buffer_HTTP_Stop;i++) {
        snprintf_P(Buffer, sizeof(Buffer), PSTR("%02x"), (byte)Buffer_HTTP[i]);
        tft.print(Buffer);
        tft.print(F(" "));
        j++;
        if (j>9) {
          j=0;
          tft.println();
        }
      }
      tft.println();
      tft.println();
      tft.print(F("Buffer_HTTP_Stop = "));
      tft.println(Buffer_HTTP_Stop);
 
      if (nb_ai>0) {
        tft.print(F("Appels :"));
        tft.println(nb_ai);
      }
      j=0;
      for (i=0;i<nb_ai;i++) {
        tft.print(ai_ind[i]);
        tft.print(F(":"));
        tft.print(ai[i]);
        j++;
        if (j>4) {
          j=0;
          tft.println();
        }else{
            tft.print(F("  "));
        }
      }
*/
      // --------------------------------------------------------------------------------------------------
 
    } else {
      // En cas d'erreur, on affiche et on recommence :
      tft.fillScreen(0);
      tft.setCursor(0, 0);
      tft.print(F("Erreur "));
      tft.print(err_code);
      delay(250);
    }
  tft.tftSpiEnd();
  } while(err_code!=0);
}
 
/*
void AfficherBMP (byte mode) {
  int i;
  unsigned int CoulBG;
  i = LireUInt9(); // La position du bitmap dans Buffer_RAM est dans Buffer_HTTP
  LireXY(LIRE_X1_Y1); // X1 et Y1 sont dans Buffer_HTTP
  if (mode == AfficherBmpBicolor) {
    CoulBG = Couleur[LireUInt8()];
  }else{
    CoulBG = Couleur[Palette];
  }
  tft.drawBitmap(X1, Y1, (byte*)(Buffer_RAM + i + 2), Buffer_RAM[i], Buffer_RAM[i+1], Couleur[coul_index], CoulBG, mode!=AfficherBmpSansBG, LireUInt8());
}
*/
 
void LireEntree(byte mode) {
  int pin;
  Status = 4;
  if (ReadedPinIndex<MaxReadedPin) {
    if (mode==LireEntreeLumiere) {
      pin = AMBIANT_LIGHT;
    }else{
      pin = LireUInt8();
    }
    pinMode(pin, INPUT);
    ReadedPin[ReadedPinIndex] = pin;
    if (mode==LireEntreeNumerique) {
      ReadedPinValue[ReadedPinIndex] = digitalRead(pin);
    }else{
      ReadedPinValue[ReadedPinIndex] = analogRead(pin);
    }
    ReadedPinIndex++;
  }
}
 
unsigned int CouleurDegrade(int i) {
  int R;
  int G;
  int B;
  R = int(C2R * i/L + C1R * (L-i)/L);
  G = int(C2G * i/L + C1G * (L-i)/L);
  B = int(C2B * i/L + C1B * (L-i)/L);
  /*
  if (R>31) {R=31;}
  if (G>63) {R=63;}
  if (B>31) {B=31;}
  */
  return (R << 11) | (G << 5) | B;
}
 
int PrintString() {
  int i;
  int j;
  Buffi++;
  tft.print(Buffer_HTTP + Buffi);
  for (i=Buffi;i<Buffer_HTTP_Stop;i++) {
    if (Buffer_HTTP[i]==0) {
      j = i - Buffi;
      Buffi = i;
      return j;
    }
  }
  return -1;
}
 
byte LireUByte() {
  Buffi++;
  return Buffer_HTTP[Buffi]; 
}
 
int LireUInt8() {
  Buffi++;
  return (byte)Buffer_HTTP[Buffi];
}
 
int LireUInt9() {
  // Entier compris entre 0 et 510 - Occupe un octet si inférieur à 255
  int tmp;
  Buffi++;
  tmp = (byte)Buffer_HTTP[Buffi];
  if (tmp==255) {
    Buffi++;
    tmp += (byte)Buffer_HTTP[Buffi];
  }
  return tmp;  
}
 
/*
int LireUInt9_RAM() {
  // Entier compris entre 0 et 510 - Occupe un octet si inférieur à 255
  int tmp;
  tmp = (byte)Buffer_RAM[Buffiram];
  Buffiram++;
  if (tmp==255) {
    tmp += (byte)Buffer_RAM[Buffiram];
    Buffiram++;
  }
  return tmp;  
}
*/
 
unsigned int LireUInt16() {
  byte MSB;
  byte LSB;
  Buffi+=2;
  MSB = Buffer_HTTP[Buffi-1];
  LSB = Buffer_HTTP[Buffi];
  return (MSB<<8) + LSB;
}
 
void LireXY(int num) {
  int tmpX;
  int tmpY;
  tmpX = LireUInt9();
  tmpY = LireUInt9() ;
  switch(num) {
  case LIRE_X1_Y1:
    X1=tmpX;
    Y1=tmpY;
    break;
  case LIRE_X2_Y2:
    X2=tmpX;
    Y2=tmpY;
    break;
  case LIRE_X3_Y3:
    X3=tmpX;
    Y3=tmpY;
    break;
  case LIRE_W1_H1:
    W1=tmpX;
    H1=tmpY;
    break;
  case LIRE_W2_H2:
    W2=tmpX;
    H2=tmpY;
    break;
  }    
}
Alors ça ne fonctionne pas bien et je sèche un peu...

J'arrive à détecter une touche sur l'écran via la broche IRQ, mais mon serveur ne reçoit à chaque frappe sur l'écran les valeurs X=0 et Y=319 quel que soit l'endroit où on a touché l'écran tactile...

Tout le reste fonctionne (affichage, shield Ethernet, ...)

S'agissant des branchements, j'ai simplement :
- laissé la broche IRQ de la dalle tactile câblée comme avant
- laissé la broche CS de la dalle tactile câblée comme avant
- câblé la broche MOSI de la dalle tactile en parallèle sur la broche MOSI de l'écran TFT
- câblé la broche MISO de la dalle tactile en parallèle sur la broche MISO de l'écran TFT
- câblé la broche CK de la dalle tactile en parallèle sur la broche CK de l'écran TFT

Je ne comprend pas ce qui cloche... J'ai essayé de baisser la vitesse du bus SPI pour la dalle tactile sans succès.

Je ne dois pas être loin de la solution car tout le reste fonctionne, y compris l'écran TFT et le shield Ethernet qui utilisent le hardware SPI

Ce passage au hardware SPI est plus "propre" et fait économiser 746 octets de ROM ainsi que 3 broches I/O, ce n'est pas négligeable.

A bientôt

A bientôt