McMajan Library Pack  v 2.00
Improve your Arduino !
Ss_hc595.cpp
Go to the documentation of this file.
1 #include <Ss_hc595.h>
2 
3 /** \brief costructor
4  * \param latch ST (pin 12 of 74HC595) - Latch - Storage register clock
5  * \param clock SH (pin 11 of 74HC595) - Shift register clock
6  * \param data DS (pin 14 of 74HC595) - Serial Data input
7  */
8 
9 
10 hc595::hc595(uint8_t latch,uint8_t clock,uint8_t data,uint8_t num)
11 {
12  latchPin=latch;
13  clockPin=clock;
14  dataPin=data;
15  Buffer=(uint8_t*)malloc(num); // num is number of 74HC595 connected
16  for(uint8_t i=0;i<num;i++) Buffer[i]=0;
17  pinMode(latchPin, OUTPUT);
18  pinMode(dataPin, OUTPUT);
19  pinMode(clockPin, OUTPUT);
20  num_595=num;
21 
22  b_Latch = digitalPinToBitMask(latchPin);;
23  //b_Clock = digitalPinToBitMask(clockPin);;
24  //b_Data = digitalPinToBitMask(dataPin);;
25 
26 
27  p_Latch=(uint8_t *)portOutputRegister(digitalPinToPort(latchPin));
28  //p_Clock=(uint8_t *)portOutputRegister(digitalPinToPort(clockPin));
29  //p_Data=(uint8_t *)portOutputRegister(digitalPinToPort(dataPin));
30 
31 }
32 /*
33 hc595::~hc595()
34 {
35  free(Buffer);
36  Buffer=0;
37 }*/
38 
39 /** \brief internal function, don't use direcly
40  */
41 
42 void hc595::PulseE(uint8_t num)
43 {
44  bitWrite(Buffer[num],3,LOW); // set enable pin to low
45  Send595();
46  delayMicroseconds(1);//delayMicroseconds(1); // >450ns
47  //__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); // fanne 8
48  bitWrite(Buffer[num],3,HIGH); // set enable pin to high
49  Send595();
50  delayMicroseconds(1);//delayMicroseconds(1); // >450ns
51  //__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
52  bitWrite(Buffer[num],3,LOW); // set enable pin to low
53  Send595();
54  delayMicroseconds(38); // > 37us
55 }
56 
57 /** \brief It sends the internal buffer to the shift register chain. This produce a update of all outputs of all shift registers.
58  */
59 void hc595::Send595(void)
60 {
61  #ifdef HC595_DP
62 
63  // latch,clock,data - 2, 4, 7
64 
65  PORTD &= ~ B0000100; // B4 LOW - Latch on pin 12
66  for( uint8_t i=num_595;i;i--)
67  {
68  //FastshiftOut(dataPin, clockPin, Buffer[i-1]);//DirectshiftOut(Buffer[i-1]);//MSBFIRST
69 
70 
71  register uint8_t k;
72  register uint8_t tmp=128; //1<<7
73  uint8_t send;
74  for (k = 8; k ; k--)
75  {
76  send=((uint8_t)Buffer[i-1] &tmp);s
77  if(send) PORTD |= B10000000; // 7H
78  else PORTD &= ~ B10000000; //7L
79  PORTD |= B00010000;//f_FastdigitalWrite(clockPin, HIGH);//fastandfast(clockPin, HIGH);// D4H
80  PORTD &= ~ B00010000;//f_FastdigitalWrite(clockPin, LOW);//fastandfast(clockPin, LOW);// D4L
81  tmp=tmp>>1;
82  }
83 
84 
85 
86 
87  }
88 
89 
90 
91  PORTD |= B0000100; // D2 HIGH - Latch on pin 4
92  #else
93  *p_Latch &= ~(uint8_t)b_Latch;//DirectdigitalWrite(b_Latch,p_Latch, LOW); //FastdigitalWrite(latchPin, LOW);//*p_Latch &= ~b_Latch; //
94  for(register uint8_t i=num_595;i;i--) FastshiftOut(dataPin, clockPin, Buffer[i-1]);//DirectshiftOut(Buffer[i-1]);//MSBFIRST
95  *p_Latch |=(uint8_t) b_Latch;//DirectdigitalWrite(b_Latch,p_Latch, HIGH);//FastdigitalWrite(latchPin, HIGH);//*p_Latch |= b_Latch;///
96  #endif
97 }
98 /** \brief It works as the sum of Set595Pin and the Send595, in the sense that sets the 8-bit and sends them directly to the shift register.
99  *If you have only one shift register to edit you should use this function. If you need to change more than one at the same time you should use two or more Set595 and eventually Send595 at the end.
100  * \param val is the 8 bit buffer to fill relative 74HC595
101  * \param display is the number of shift register on the chain (0 is the first!).
102  */
103 void hc595::Send595Pin(uint8_t val,uint8_t display)
104 {
105  Set595Pin(val,display);
106  Send595();
107 }
108 
109 /** \brief Using this function you can set every bit of the buffer of a single 74HC595 internal buffer using single bits.
110  * \param D7-0 are single true or false values of single bits
111  * \param num is the number of shift register in the chain.
112  */
113 void hc595::Set595Pin(bool D7,bool D6,bool D5,bool D4,bool D3,bool D2,bool D1,bool D0,uint8_t num)
114 {
115  Buffer[num]=(D7<<7)+(D6<<6)+(D5<<5)+(D4<<4)+(D3<<3)+(D2<<2)+(D1<<1)+D0;
116 }
117 /** \brief set internal buffer of single 74hc595 (without update the real chip status but only internal buffer
118  * \param val is the 8 bit buffer to fill relative 74HC595
119  * \param display is the number of shift register on the chain (0 is the first!).
120  */
121 void hc595::Set595Pin(uint8_t val,uint8_t num)
122 {
123  Buffer[num]=val;
124 }
125 /** \brief Sets the free pins (2 and 0) of 74HC595 connected to a display. ,
126  * \param pin is the pin (0 or 2)
127  * \params status is the state (HIGH o LOW)
128  * \param sr and sr is the shift register number (from 0).
129  */
130 void hc595::Lcd_SetFreePin(uint8_t pin, bool status,uint8_t sr)
131 {
132  bitWrite(Buffer[sr],pin,status);
133  Send595();
134 }
135 /** \brief Reset of the display
136  * \param options You can combite (with |) more of this:
137  * <br>LCD595_BASIC_DISPLAY_INIT: standard reset
138  * <br>LCD595_USEFONT_5X10: use the 5x10 font instead the 5x8
139  * <br>LCD595_MORELINES: use displays with more than one line.
140  * <br>If you leave a null value, the standard option is: LCD595_BASIC_DISPLAY_INIT | LCD595_USEFONT_5X10 | LCD595_MORELINES
141  * \params num is the number of shift register in the chain
142  */
143 void hc595::DisplayReset(uint8_t options,uint8_t num)
144 {
146  //procedura di reset
147  delayMicroseconds(4100); // attesa iniziale....40ms ( ho usato tempi abbondanti
148 
149  SetLcdPin(0,0,1,1,num); // invio 0011
150  PulseE(num);
151  delayMicroseconds(4200); // 4.1ms
152 
153  SetLcdPin(0,0,1,1,num); // reinvio 0011
154  PulseE(num);
155  delayMicroseconds(110); // 100us
156 
157  SetLcdPin(0,0,1,1,num); // reinvio 0011
158  PulseE(num);
159 
160  SetLcdPin(0,0,1,0,num); // ...settiamo i 4 bit...
161  PulseE(num);
162 
163 
164  SendLcdCommand(options,num); // Inizializzazione con font e righe : 42 0 0 1 DL N F 0 0 (DL: 0 (4bit), N=1 (due righe) F:5x8 (0) vs 15x10 (1))
165  SendLcdCommand(LCD595_DISPLAY_ON,num); // accendo il display
166  SendLcdCommand(LCD595_DISPLAY_CLEAR,num); // clear
167 
168 }
169 /** \brief Write a string on the specificated display starting from actual position
170  * \param buff is the buffer to write (null terminated!)
171  * \params display is the shift register number in the chain.
172  */
173 void hc595::DisplayWrite(const char *buff,uint8_t display)
174 {
175  int ln=strlen(buff);
176  for(int i=0;i<ln;i++) {DisplayChar(buff[i],display);}
177 
178 }
179 /** \brief Write a single char on the specificated display starting from actual position
180  * \param buff is the char to write
181  * \params display is the shift register number in the chain.
182  */
183 void hc595::DisplayChar(uint8_t buff,uint8_t display)
184 {
185  //scrivo una lettera OPPURE invio dati generici per altri scopi
186  SetLcdRS(HIGH,display); // porto RS ad HIGH per indicare l'invio di DATI
187  SetHLcd(buff,display);
188  PulseE(display);
189  SetLLcd(buff,display);
190  PulseE(display);
191  delayMicroseconds(37); // 37us
192 }
193 /// @cond nodoxy
194 
195 void hc595::SetLcdPin(bool D7,bool D6,bool D5,bool D4,uint8_t num)
196 {
197  bitWrite(Buffer[num],7,D7);
198  bitWrite(Buffer[num],6,D6);
199  bitWrite(Buffer[num],5,D5);
200  bitWrite(Buffer[num],4,D4);
201 }
202 
203 /// @endcond
204 
205 /** \brief move virtual cursor to x,y position
206  * \param x is the column
207  * \params y is the row
208  * \params type for now it's 1 or 2, depend of the specific display (different internal addressing). If you note x,y don't correspond as you want, change this parameter.
209  * \display
210  */
211 void hc595::SetCursor(uint8_t X, uint8_t Y,uint8_t type,uint8_t display)
212 {
213  int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; //type 1
214  if(type==2) {row_offsets[2]=0x10; row_offsets[3]=0x50;}
215 
216  if(Y>3) Y=Y%4;
217  uint8_t val;
218  val=(0x80 | (X + row_offsets[Y]));
219  SendLcdCommand(val,display);
220 }
221 
222 /// @cond nodoxy
223 void hc595::SetDDRAM_Address(uint8_t address,uint8_t display)
224 {
225  uint8_t val=(0x80 | address);
226  SendLcdCommand(val,display);
227 }
228 /// @endcond
229 
230 
231 /** \brief Used to redefine some custom characters. The char is the number of the character to redefine (0-7). Array is a 8bytes array with the bitmap of new character. sr is the number of the shift register.
232 
233  * \params address is the char you want to change (0-7)
234  * \params map is the buffer
235  * \param display is the number of register in the chain
236  *
237  * \code
238  * byte MyChar[8] = {0,10,21,10,0,17,14,3};
239  * My595.CreateChar(0,MyChar,3);
240  * My595.DisplayChar(0,3);
241  *
242  * \endcode
243  */
244 void hc595::CreateChar(uint8_t address,uint8_t map[],uint8_t display)
245 {
246  address &= 0x7; // we have only 8 locations 0-7
247  SendLcdCommand(0x40 | (address << 3),display);
248  for (int i=0; i<8; i++) DisplayChar(map[i],display);
249 
250 }
251 
252 /** \brief This function is useful to send directly some commands to the display.
253  *\params val This is the option parameter which is a char in which every bit will be sent to the display.
254  There are some pre-set:
255  <br>LCD595_DISPLAY_ON_CB: Switch on the display with blinking cursor on.
256  <br>LCD595_DISPLAY_ON_C: Switch on the display with NOT blinking cursor.
257  <br>LCD595_DISPLAY_ON_B: Switch on the display with last char blinking.
258  <br>LCD595_DISPLAY_ON: Switch on display without cursor.
259  <br>LCD595_DISPLAY_OFF: Switch off the display
260  <br>LCD595_DISPLAY_CLEAR: Cleans the display.
261 
262  * \params display is the shift register number on the chain
263  *
264  * \code
265  * My595.SendLcdCommand(LCD595_DISPLAY_ON_C,3);
266  *
267  * \endcode
268  */
269 
270 
271 
272 
273 
274 
275 
276  void hc595::SendLcdCommand(uint8_t val,uint8_t display)
277  {
278  SetLcdRS(LOW,display);
279  SetHLcd(val,display);
280  PulseE(display);
281  SetLLcd(val,display);
282  PulseE(display);
283  delayMicroseconds(37); // 37us
284  if(val==LCD595_DISPLAY_CLEAR) delayMicroseconds(15300);//delay(2); //1.52ms
285 }
286 /// @cond nodoxy
287 
288  void hc595::SetLcdRS(bool Val,uint8_t display)
289  {
290  bitWrite(Buffer[display],1,Val); // porto RS ad HIGH per indicare l'invio di DATI o LOW per i comandi
291 
292  }
293 
294  void hc595::SetHLcd(uint8_t val,uint8_t display)
295  {
296  SetLcdPin(bitRead(val,7),bitRead(val,6),bitRead(val,5),bitRead(val,4),display); // primi 4
297  }
298 
299  void hc595::SetLLcd(uint8_t val,uint8_t display)
300  {
301  SetLcdPin(bitRead(val,3),bitRead(val,2),bitRead(val,1),bitRead(val,0),display); // ultimi 4
302  }
303 
304 /// @endcond
305 
306 /*
307 inline void hc595::DirectdigitalWrite(uint8_t bit, uint8_t * out,uint8_t val)
308 {
309  val?*out |= (uint8_t)bit:*out &= ~(uint8_t)bit;
310  //if (val != LOW) *out |= bit;
311  //else *out &= ~bit;
312 
313 }*/
314 /*
315 void hc595::DirectshiftOut(const uint8_t val)
316 {
317  for (uint8_t i = 0; i < 8; i++)
318  {
319  ( (val & (1 << (7 - i))) != LOW)?*p_Data |= (uint8_t)b_Data:*p_Data &= ~(uint8_t)b_Data;
320  //hc595_DirectdigitalWrite(b_Data,p_Data, !!(val & (1 << (7 - i))));
321  //( !!(val & (1 << (7 - i))) != LOW)?*p_Data |= b_Data:*p_Data &= ~b_Data;
322  //f_FastdigitalWrite(dataPin, !!(val & (1 << (7 - i))));
323 
324  *p_Clock |= (uint8_t)b_Clock; //DirectdigitalWrite(b_Clock,p_Clock, HIGH); //f_FastdigitalWrite(clockPin, HIGH);
325  *p_Clock &= ~(uint8_t)b_Clock;//DirectdigitalWrite(b_Clock,p_Clock, LOW);//f_FastdigitalWrite(clockPin, LOW);
326  }
327 }
328 */
void SetLcdRS(bool, uint8_t)
Definition: Ss_hc595.cpp:288
#define LCD595_DISPLAY_ON
Definition: Ss_hc595.h:31
void SendLcdCommand(uint8_t, uint8_t)
This function is useful to send directly some commands to the display. val This is the option parame...
Definition: Ss_hc595.cpp:276
void DisplayWrite(const char *, uint8_t)
Write a string on the specificated display starting from actual position.
Definition: Ss_hc595.cpp:173
void DisplayReset(uint8_t, uint8_t)
Reset of the display.
Definition: Ss_hc595.cpp:143
void SetDDRAM_Address(uint8_t, uint8_t)
Definition: Ss_hc595.cpp:223
hc595(uint8_t, uint8_t, uint8_t, uint8_t)
costructor
Definition: Ss_hc595.cpp:10
#define LCD595_BASIC_DISPLAY_INIT
Definition: Ss_hc595.h:35
#define LCD595_DISPLAY_CLEAR
Definition: Ss_hc595.h:25
#define LCD595_MORELINES
Definition: Ss_hc595.h:37
void Set595Pin(bool, bool, bool, bool, bool, bool, bool, bool, uint8_t)
Using this function you can set every bit of the buffer of a single 74HC595 internal buffer using sin...
Definition: Ss_hc595.cpp:113
void Set595Pin(uint8_t, uint8_t)
set internal buffer of single 74hc595 (without update the real chip status but only internal buffer ...
Definition: Ss_hc595.cpp:121
void SetLcdPin(bool, bool, bool, bool, uint8_t)
Definition: Ss_hc595.cpp:195
#define FastshiftOut(a, b, d)
void SetHLcd(uint8_t, uint8_t)
Definition: Ss_hc595.cpp:294
#define LCD595_USEFONT_5X10
Definition: Ss_hc595.h:36
void SetCursor(uint8_t, uint8_t, uint8_t, uint8_t)
move virtual cursor to x,y position
Definition: Ss_hc595.cpp:211
void CreateChar(uint8_t, uint8_t[], uint8_t)
Used to redefine some custom characters. The char is the number of the character to redefine (0-7)...
Definition: Ss_hc595.cpp:244
void Send595Pin(uint8_t, uint8_t)
It works as the sum of Set595Pin and the Send595, in the sense that sets the 8-bit and sends them dir...
Definition: Ss_hc595.cpp:103
void SetLLcd(uint8_t, uint8_t)
Definition: Ss_hc595.cpp:299
void Send595(void)
It sends the internal buffer to the shift register chain. This produce a update of all outputs of all...
Definition: Ss_hc595.cpp:59
void Lcd_SetFreePin(uint8_t, bool, uint8_t)
Sets the free pins (2 and 0) of 74HC595 connected to a display. ,.
Definition: Ss_hc595.cpp:130
void PulseE(uint8_t)
internal function, don&#39;t use direcly
Definition: Ss_hc595.cpp:42
void DisplayChar(uint8_t, uint8_t)
Write a single char on the specificated display starting from actual position.
Definition: Ss_hc595.cpp:183