1006 typedef union { 1007 struct { 1008 unsigned LATA0 :1; 1009 unsigned LATA1 :1; 1010 unsigned LATA2 :1; 1011 unsigned LATA3 :1; 1012 unsigned LATA4 :1; 1013 unsigned LATA5 :1; 1014 unsigned LATA6 :1; 1015 unsigned LATA7 :1; 1016 }; 1017 ...... 1048 } LATAbits_t; 1049 extern volatile LATAbits_t LATAbits @ 0xF89;
56 #define Row0 LATAbits.LATA1 57 #define Row1 LATAbits.LATA2 58 #define Row2 LATAbits.LATA3 59 #define Row3 LATAbits.LATA4 60 #define Row4 LATAbits.LATA5 61 #define Row5 LATCbits.LATC0 62 #define Row6 LATCbits.LATC1 63 #define Row7 LATBbits.LATB1 64 #define Row8 LATBbits.LATB2 65 #define Row9 LATBbits.LATB3
32 void SetRow(unsigned char Row) 33 {// from 0 to 9, enable one row at a time to scan matrix 34 switch (Row) 35 { 36 case 0: 37 Row0 = ON; 38 break; 39 40 case 1: 41 Row1 = ON; 42 break; 43 44 case 2: 45 Row2 = ON; 46 break; 47 48 case 3: 49 Row3 = ON; 50 break; 51 52 case 4: 53 Row4 = ON; 54 break; 55 56 case 5: 57 Row5 = ON; 58 break; 59 60 case 6: 61 Row6 = ON; 62 break; 63 64 case 7: 65 Row7 = ON; 66 break; 67 68 case 8: 69 Row8 = ON; 70 break; 71 72 case 9: 73 Row9 = ON; 74 break; 75 76 default: 77 SetRowOff(); 78 break; 79 } 80 }
170 void WordSetting() 171 {// set the matrix with the words according to the new time 172 int i; 173 174 for(i=0; i<=MAXROW; i++) 175 {// reset the matrix 176 Matrix[i]=0; 177 } 178 179 if(Min <= 30) 180 {// after half hour the word is "to" the next hour, before is "after" 181 Matrix[6]=0b000000011110; // E 182 } 183 else 184 { 185 Hour++; 186 Matrix[7]=0b100000000000; // MENO 187 } 188 189 switch(Min / 5) 190 { 191 case 1: 192 case 11: 193 Matrix[8] = Matrix[8] | 0b000001111110;// CINQUE 194 break; 195 196 case 2: 197 case 10: 198 Matrix[9] = Matrix[9] | 0b111100000000;// DIECI 199 break; 200 201 case 3: 202 case 9: 203 Matrix[7] = Matrix[7] | 0b001101111110;// UN QUARTO 204 break; 205 206 case 4: 207 case 8: 208 Matrix[8] = Matrix[8] | 0b111110000000;// VENTI 209 break; 210 211 case 5: 212 case 7: 213 Matrix[8] = Matrix[8] | 0b111111111110;// VENTICINQUE 214 break; 215 216 case 6: 217 Matrix[9] = Matrix[9] | 0b000000111110;// MEZZA 218 break; 219 220 default: 221 break; 222 } 223 224 if(!TimeSync)// light up points only if RTC time is in sync with INRIM 225 { 226 switch(Min % 5) 227 { 228 case 1: 229 Matrix[0] = Matrix[0] | 0b000000000001;// first point 230 break; 231 232 case 2: 233 Matrix[0] = Matrix[0] | 0b000000000001;// first point 234 Matrix[1] = Matrix[1] | 0b000000000001;// add second point 235 break; 236 237 case 3: 238 Matrix[0] = Matrix[0] | 0b000000000001;// first point 239 Matrix[1] = Matrix[1] | 0b000000000001;// add second point 240 Matrix[2] = Matrix[2] | 0b000000000001;// add third point 241 break; 242 243 case 4: 244 Matrix[0] = Matrix[0] | 0b000000000001;// first point 245 Matrix[1] = Matrix[1] | 0b000000000001;// add second point 246 Matrix[2] = Matrix[2] | 0b000000000001;// add third point 247 Matrix[3] = Matrix[3] | 0b000000000001;// add fourth point 248 break; 249 250 default: 251 break; 252 } 253 } 254 255 Hour = Hour % 12; 256 257 if(Hour == 1) 258 { 259 Matrix[1] = Matrix[1] | 0b101000000000;// E' L' 260 } 261 else 262 { 263 Matrix[0] = Matrix[0] | 0b111101101110;// SONO LE ORE 264 } 265 266 switch(Hour) 267 { 268 case 1: 269 Matrix[1] = Matrix[1] | 0b000111000000;// UNA 270 break; 271 272 case 2: 273 Matrix[1] = Matrix[1] | 0b000000011000;// DUE 274 break; 275 276 case 3: 277 Matrix[2] = Matrix[2] | 0b111000000000;// TRE 278 break; 279 280 case 4: 281 Matrix[5] = Matrix[5] | 0b111111100000;// QUATTRO 282 break; 283 284 case 5: 285 Matrix[6] = Matrix[6] | 0b111111000000;// CINQUE 286 break; 287 288 case 6: 289 Matrix[5] = Matrix[5] | 0b000000001110;// SEI 290 break; 291 292 case 7: 293 Matrix[4] = Matrix[4] | 0b000000111110;// SETTE 294 break; 295 296 case 8: 297 Matrix[2] = Matrix[2] | 0b000111100000;// OTTO 298 break; 299 300 case 9: 301 Matrix[2] = Matrix[2] | 0b000000011110;// NOVE 302 break; 303 304 case 10: 305 Matrix[3] = Matrix[3] | 0b111110000000;// DIECI 306 break; 307 308 case 11: 309 Matrix[3] = Matrix[3] | 0b000001111110;// UNDICI 310 break; 311 312 case 0: 313 Matrix[4] = Matrix[4] | 0b111111000000;// DODICI 314 break; 315 316 default: 317 break; 318 } 319 320 SetColB(); 321 }
But the translation (to the left) is to heavy to be performed every 1ms, because it requires a lot of masking operations to set each port.
For this reason it is performed only at each change of display, i.e.: every minute and the result is buffered in a matrix of unsigned int. This wastes more memory (one int for each bit) but...
82 void SetColB(void) 83 {// pre-fill the matrix with bytes instead of bits. 84 // This wastes memory but saves a lot of time during runtime matrix scan 85 char Col; 86 char Row; 87 unsigned int Mask; 88 89 for(Row = MINROW; Row <= MAXROW; Row++) 90 { 91 for(Col = MinCol; Col <= MaxCol; Col++) 92 { 93 Mask=BitMask[Col] & Matrix[Row]; 94 95 if(Mask) 96 { 97 MatrixB[Row][MaxCol-Col] = ON; 98 } 99 else 100 { 101 MatrixB[Row][MaxCol-Col] = OFF; 102 } 103 } 104 } 105 }
107 void SetCol(unsigned char Row) 108 {/* from 'A' to 'L', enable all the column to light all the LEDs interested 109 the byte matrix is pre-computed when LEDs to display change (every minute) 110 this saves a lot of time during 1ms column scan 111 112 * RD0 = Column A 113 * RD1 = Column B 114 * RD2 = Column C 115 * RD3 = Column D 116 * RD4 = Column E 117 * RD5 = Column F 118 * RD6 = Column G 119 * RD7 = Column H 120 * 121 * RE0 = Column I 122 * RE1 = Column J 123 * RE2 = Column K 124 * 125 * RC5 = Column L 126 */ 127 128 ColA = MatrixB[Row][11]; 129 ColB = MatrixB[Row][10]; 130 ColC = MatrixB[Row][9]; 131 ColD = MatrixB[Row][8]; 132 ColE = MatrixB[Row][7]; 133 ColF = MatrixB[Row][6]; 134 ColG = MatrixB[Row][5]; 135 ColH = MatrixB[Row][4]; 136 137 LATD = Dbits.Port; 138 139 ColI = MatrixB[Row][3]; 140 ColJ = MatrixB[Row][2]; 141 ColK = MatrixB[Row][1]; 142 143 LATE = Ebits.Port; 144 145 ColL = MatrixB[Row][0]; 146 147 LATC = PORTC | Cbits.Port; 148 }
182 // Low priority interrupt vector 183 void interrupt low_priority low_isr (void) 184 { 185 ....... 244 245 if (PIR1bits.ADIF) 246 {// A new AD value has been read 247 PIR1bits.ADIF=0; // reset interrupt flag 248 DutyCycle=(ADRESH*LightIndx)>>8;//only the highest 8 bits are read 249 //>>8 to convert back index to int 250 } 251 252 }
160 void SetTimer1(unsigned char DutyCycle) 161 { 162 //set both High and Low registers for Timer1 163 int Count = DutyTab[DutyCycle]; 164 TMR1H = Count >> 8; // byte High 165 TMR1L = Count; // byte Low 166 T1CONbits.TMR1ON=1; 167 }
...converted in time with the aid of DutyTab[] values.
In this way the TMR1 switches off the columns dimming the LEDs brightness according to the computed duty cycle.
323 void TestMatrix() 324 { 325 static unsigned char Xcol; 326 static unsigned char Yrow; 327 int i; 328 static int j = 0; 329 static int k = 0; 330 331 332 for(i=MINROW; i<=MAXROW; i++) 333 {// reset the matrix 334 Matrix[i]=0; 335 } 336 337 switch(j) 338 { 339 case 0: // char display 340 WriteMatrixChar('G', 'O', 7, 1); 341 TestTime = 5000; 342 j++; 343 break; 344 345 case 1: // dot by dot 346 Matrix[Yrow]=0b0000100000000000 >> Xcol; 347 if((++Xcol)>MaxCol) 348 { 349 Xcol = MinCol; 350 if((++Yrow)>MAXROW) 351 { 352 Yrow=MINROW; 353 j++; 354 } 355 } 356 TestTime = 100; 357 break; 358 359 case 2: // row by row 360 Matrix[Yrow]=0b0000111111111111; 361 if((++Yrow)>MAXROW) 362 { 363 Yrow=MINROW; 364 j++; 365 } 366 TestTime = 300; 367 break; 368 369 case 3: //column by column 370 Matrix[0]=0b0000100000000000 >> Xcol; 371 Matrix[1]=0b0000100000000000 >> Xcol; 372 Matrix[2]=0b0000100000000000 >> Xcol; 373 Matrix[3]=0b0000100000000000 >> Xcol; 374 Matrix[4]=0b0000100000000000 >> Xcol; 375 Matrix[5]=0b0000100000000000 >> Xcol; 376 Matrix[6]=0b0000100000000000 >> Xcol; 377 Matrix[7]=0b0000100000000000 >> Xcol; 378 Matrix[8]=0b0000100000000000 >> Xcol; 379 Matrix[9]=0b0000100000000000 >> Xcol; 380 if((++Xcol)>MaxCol) 381 { 382 Xcol = MinCol; 383 j++; 384 } 385 TestTime = 300; 386 break; 387 388 case 4: //diagonal left 389 Matrix[0]=0b0000100000000000 >> Xcol; 390 Matrix[1]=0b0000010000000000 >> Xcol; 391 Matrix[2]=0b0000001000000000 >> Xcol; 392 Matrix[3]=0b0000000100000000 >> Xcol; 393 Matrix[4]=0b0000000010000000 >> Xcol; 394 Matrix[5]=0b0000000001000000 >> Xcol; 395 Matrix[6]=0b0000000000100000 >> Xcol; 396 Matrix[7]=0b0000000000010000 >> Xcol; 397 Matrix[8]=0b1000000000001000 >> Xcol; 398 Matrix[9]=0b0100000000000100 >> Xcol; 399 if((++Xcol)>MaxCol) 400 { 401 Xcol = MinCol; 402 j++; 403 } 404 TestTime = 300; 405 break; 406 407 case 5: //diagonal right 408 Matrix[0]=0b0000000000000100 << Xcol; 409 Matrix[1]=0b0000000000001000 << Xcol; 410 Matrix[2]=0b0000000000010000 << Xcol; 411 Matrix[3]=0b0000000000100000 << Xcol; 412 Matrix[4]=0b0000000001000000 << Xcol; 413 Matrix[5]=0b0000000010000000 << Xcol; 414 Matrix[6]=0b0000000100000000 << Xcol; 415 Matrix[7]=0b0000001000000000 << Xcol; 416 Matrix[8]=0b0000010000000001 << Xcol; 417 Matrix[9]=0b0000100000000010 << Xcol; 418 if((++Xcol)>MaxCol) 419 { 420 Xcol = MinCol; 421 j++; 422 } 423 TestTime = 300; 424 break; 425 426 case 6: //all LEDs on 427 if(k%2) 428 { 429 Matrix[0]=0XFFFF; 430 Matrix[1]=0XFFFF; 431 Matrix[2]=0XFFFF; 432 Matrix[3]=0XFFFF; 433 Matrix[4]=0XFFFF; 434 Matrix[5]=0XFFFF; 435 Matrix[6]=0XFFFF; 436 Matrix[7]=0XFFFF; 437 Matrix[8]=0XFFFF; 438 Matrix[9]=0XFFFF; 439 } 440 else 441 { 442 Matrix[0]=0; 443 Matrix[1]=0; 444 Matrix[2]=0; 445 Matrix[3]=0; 446 Matrix[4]=0; 447 Matrix[5]=0; 448 Matrix[6]=0; 449 Matrix[7]=0; 450 Matrix[8]=0; 451 Matrix[9]=0; 452 } 453 454 if((++k)>8) 455 { 456 k = 0; 457 j++; 458 } 459 TestTime = 1000; 460 break; 461 462 default: 463 j=0; 464 TestTime = 300; 465 break; 466 } 467 468 // Matrix[0]=0b0000111111111111; 469 470 SetColB(); 471 }
This procedure is compiled just when needed in order to test all the matrix hardware and functionality.
It also includes the display of the characters using a 7x5 font.
With the methods used to drive the matrix has been really easy to use one of the many font descriptions available on the Net. The only problem was to swap rows and columns because normally a columns scanning is used instead of rows scanning as I do. This task has been done using this worksheet.
To the right a video that shows how this test works.
Software
The rows, from 0 to 9, are selected on by one with 1ms period, resulting in a 10ms total period. The 100Hz frame rate is good to have a flicker free display.
The columns, from A to L, are selected in parallel when
the corresponding row is lighted up.
Beside an example of the PIC header file that shows how the ports are mnemonically defined. The example is for PORTA.
The whole MPLABX C project
for the PIC18F4620
is available as an open source at
GitHub repository