/** * \file Dual DAC outputs for driving a vector scope. * */#include <avr/io.h>#include <avr/pgmspace.h>#include <avr/interrupt.h>#include <stdint.h>#include <string.h>#include <util/delay.h>#include "usb_serial.h"#include "bits.h"#include "hershey.h"#include "sin_table.h"/** Track the number of miliseconds, sec, min and hour since midnight */staticvolatileuint16_tnow_ms;staticvolatileuint8_tnow_sec=30;staticvolatileuint8_tnow_min=19;staticvolatileuint8_tnow_hour=20;// Define CONFIG_HZ_IRQ to enable a timer interrupt rather than// polling the interrupt flag.#define CONFIG_HZ_IRQ/** 1000-hz overflow */#ifdef CONFIG_HZ_IRQISR(TIMER0_COMPA_vect)#elsestaticvoidnow_update(void)#endif{if(now_ms<999){now_ms+=1;return;}now_ms=0;if(now_sec<59){now_sec++;return;}now_sec=0;if(now_min<59){now_min++;return;}now_min=0;if(now_hour<23){now_hour++;return;}now_hour=0;}voidsend_str(constchar*s);uint8_trecv_str(char*buf,uint8_tsize);voidparse_and_execute_command(constchar*buf,uint8_tnum);staticuint8_thexdigit(uint8_tx){x&=0xF;if(x<0xA)returnx+'0'-0x0;elsereturnx+'A'-0xA;}staticuint8_tprintable(uint8_tx){if('A'<=x&&x<='Z')return1;if('a'<=x&&x<='z')return1;if('0'<=x&&x<='9')return1;if(x==' ')return1;return0;}staticvoidline_vert(uint8_tx0,uint8_ty0,uint8_tw){PORTB=x0;PORTD=y0;for(uint8_ti=0;i<w;i++){PORTD++;}}staticvoidline_horiz(uint8_tx0,uint8_ty0,uint8_th){PORTB=x0;PORTD=y0;for(uint8_ti=0;i<h;i++){PORTB++;}}staticvoidline(uint8_tx0,uint8_ty0,uint8_tx1,uint8_ty1){intdx;intdy;intsx;intsy;if(x0<x1){dx=x1-x0;sx=1;}else{dx=x0-x1;sx=-1;}if(y0<y1){dy=y1-y0;sy=1;}else{dy=y0-y1;sy=-1;}interr=dx-dy;while(1){PORTB=x0;PORTD=y0;if(x0==x1&&y0==y1)break;inte2=2*err;if(e2>-dy){err=err-dy;x0+=sx;}if(e2<dx){err=err+dx;y0+=sy;}}}staticinlinevoid_draw_digit(uint8_tx,uint8_ty,uint8_tval,constuint8_tscale){constpath_t*p=digits[val];while(1){uint8_tox=x+p->x/scale;uint8_toy=y+p->y/scale;while(1){p++;int8_tpx=p->x;int8_tpy=p->y;if(px==0&&py==0)return;if(px==-1&&py==-1){p++;break;}uint8_tnx=x+px/scale;uint8_tny=y+py/scale;line(ox,oy,nx,ny);ox=nx;oy=ny;}}}staticvoiddraw_digit_big(uint8_tx,uint8_ty,uint8_tval){_draw_digit(x,y,val,1);}staticvoiddraw_digit(uint8_tx,uint8_ty,uint8_tval){_draw_digit(x,y,val,2);}intmain(void){// set for 16 MHz clock#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))CPU_PRESCALE(0);// Disable the ADCADMUX=0;// initialize the USB, and then wait for the host// to set configuration. If the Teensy is powered// without a PC connected to the USB port, this // will wait forever.usb_init();while(!usb_configured())/* wait */;_delay_ms(1000);// wait for the user to run their terminal emulator program// which sets DTR to indicate it is ready to receive.while(!(usb_serial_get_control()&USB_SERIAL_DTR))continue;// discard anything that was received prior. Sometimes the// operating system or other software will send a modem// "AT command", which can still be buffered.usb_serial_flush_input();DDRB=0xFF;DDRD=0xFF;PORTB=128;PORTD=0;uint8_toff=0;charbuf[32];uint8_tpx=0;uint8_tpy=0;uint8_tcount=0;// Configure timer0 to overflow every 1 ms// CTC mode (clear counter at OCR0A, signal interrupt)TCCR0A=0|(1<<WGM01)|(0<<WGM00);TCCR0B=0|(0<<WGM02)|(0<<CS02)|(1<<CS01)|(1<<CS00);// Clk/256 @ 16 MHz => 250 ticks == 10 msOCR0A=250;#ifdef CONFIG_HZ_IRQsbi(TIMSK0,OCIE0A);sei();#endifwhile(1){#ifndef CONFIG_HZ_IRQ// If the interrupt is not in use, check the overflow bitif(bit_is_set(TIFR0,OCF0A)){sbi(TIFR0,OCF0A);now_update();}#endifif(count++==100){count=0;if(px<30)px++;elsepx=0;if(py<120)py+=3;elsepy=0;}// Draw all the digits around the outsidefor(uint8_th=0;h<24;h++){uint16_th2=h;h2=(h2*682)/64;uint8_tx=sin_lookup(h2)*7/8+128;uint8_ty=cos_lookup(h2)*7/8+128;draw_digit(x-8,y-4,h/10);draw_digit(x+2,y-4,h%10);}// Draw the hour handuint8_th=now_hour;uint8_tm=now_min;uint8_ts=now_sec;constuint8_tcx=72;constuint8_tcy=64;draw_digit_big(0+cx,cy,h/10);draw_digit_big(16+cx,cy,h%10);draw_digit_big(40+cx,cy,m/10);draw_digit_big(56+cx,cy,m%10);draw_digit_big(80+cx,cy,s/10);draw_digit_big(96+cx,cy,s%10);{uint16_th2=h;h2=(h2*682+m*11)/64;uint8_thx=sin_lookup(h2)*3/8+128;uint8_thy=cos_lookup(h2)*3/8+128;line(128,128,hx,hy);}{uint16_tm2=m;m2=(m2*273+s*4)/64;uint8_tmx=sin_lookup(m2)*5/8+128;uint8_tmy=cos_lookup(m2)*5/8+128;line(128,128,mx,my);line_horiz(mx-5,my,10);line_vert(mx,my-5,10);}// seconds to "degrees" = {uint16_ts2=s;s2=(s2*1092+now_ms)/256;uint8_tsx=sin_lookup(s2)*6/8+128;uint8_tsy=cos_lookup(s2)*6/8+128;line(128,128,sx,sy);}/* line_horiz(0,0,255); line_horiz(0,255,255); line_vert(0,0,255); line_vert(255,0,255);*/}}// Send a string to the USB serial port. The string must be in// flash memory, using PSTR//voidsend_str(constchar*s){charc;while(1){c=pgm_read_byte(s++);if(!c)break;usb_serial_putchar(c);}}