"); //-->
代码;
lcd_drive.c //***************************************************************************** // // File........: LCD_driver.c // // Author(s)...: ATMEL Norway // // Target(s)...: ATmega169 // // Compiler....: AVR-GCC 3.3.1; avr-libc 1.0 // // Description.: Functions used to control the AVR Butterfly LCD // // Revisions...: 1.0 // // YYYYMMDD - VER. - COMMENT - SIGN. // // 20021015 - 1.0 - Written for STK502 - JLL // 20030116 - 2.0 - Code adapted to AVR Butterfly - KS // 20031009 port to avr-gcc/avr-libc - M.Thomas // //***************************************************************************** #define REDUCED // Include files. #include <avr/io.h> #include <avr/pgmspace.h> #include <inttypes.h> #include <avr/interrupt.h> #include <avr/interrupt.h> // mt - for gButtonTimeout // #include "button.h" #include "LCD_driver.h" #ifndef BOOL #define BOOL char #define FALSE 0 #define TRUE (!FALSE) #endif // Variable from "button.c" to prevent button-bouncing extern unsigned char gButtonTimeout; volatile char gAutoPressJoystick = FALSE; // Used to indicate when the LCD interrupt handler should update the LCD // mt jw char gLCD_Update_Required = FALSE; volatile char gLCD_Update_Required = FALSE; // LCD display buffer (for double buffering). volatile char LCD_Data[LCD_REGISTER_COUNT]; // Buffer that contains the text to be displayed // Note: Bit 7 indicates that this character is flashing volatile char gTextBuffer[TEXTBUFFER_SIZE]; // Only six letters can be shown on the LCD. // With the gScroll and gScrollMode variables, // one can select which part of the buffer to show volatile signed char gScroll; volatile char gScrollMode; ////Start-up delay before scrolling a string over the LCD char gLCD_Start_Scroll_Timer = 0; // The gFlashTimer is used to determine the on/off // timing of flashing characters volatile char gFlashTimer = 0; // Turns on/off the colons on the LCD char gColon = 0; // Look-up table used when converting ASCII to // LCD display data (segment control) // mt __flash unsigned int LCD_character_table[] = unsigned int LCD_character_table[] PROGMEM = { 0x0A51, // '*' (?) 0x2A80, // '+' 0x0000, // ',' (Not defined) 0x0A00, // '-' 0x0A51, // '.' Degree sign 0x0000, // '/' (Not defined) 0x5559, // '0' 0x0118, // '1' 0x1e11, // '2 0x1b11, // '3 0x0b50, // '4 0x1b41, // '5 0x1f41, // '6 0x0111, // '7 0x1f51, // '8 0x1b51, // '9' 0x0000, // ':' (Not defined) 0x0000, // ';' (Not defined) 0x0000, // '<' (Not defined) 0x0000, // '=' (Not defined) 0x0000, // '>' (Not defined) 0x0000, // '?' (Not defined) 0x0000, // '@' (Not defined) 0x0f51, // 'A' (+ 'a') 0x3991, // 'B' (+ 'b') 0x1441, // 'C' (+ 'c') 0x3191, // 'D' (+ 'd') 0x1e41, // 'E' (+ 'e') 0x0e41, // 'F' (+ 'f') 0x1d41, // 'G' (+ 'g') 0x0f50, // 'H' (+ 'h') 0x2080, // 'I' (+ 'i') 0x1510, // 'J' (+ 'j') 0x8648, // 'K' (+ 'k') 0x1440, // 'L' (+ 'l') 0x0578, // 'M' (+ 'm') 0x8570, // 'N' (+ 'n') 0x1551, // 'O' (+ 'o') 0x0e51, // 'P' (+ 'p') 0x9551, // 'Q' (+ 'q') 0x8e51, // 'R' (+ 'r') 0x9021, // 'S' (+ 's') 0x2081, // 'T' (+ 't') 0x1550, // 'U' (+ 'u') 0x4448, // 'V' (+ 'v') 0xc550, // 'W' (+ 'w') 0xc028, // 'X' (+ 'x') 0x2028, // 'Y' (+ 'y') 0x5009, // 'Z' (+ 'z') 0x0000, // '[' (Not defined) 0x0000, // '\' (Not defined) 0x0000, // ']' (Not defined) 0x0000, // '^' (Not defined) 0x0000 // '_' }; /***************************************************************************** * * Function name : LCD_Init * * Returns : None * * Parameters : None * * Purpose : Initialize LCD_displayData buffer. * Set up the LCD (timing, contrast, etc.) * *****************************************************************************/ void LCD_Init (void) { LCD_AllSegments(FALSE); // Clear segment buffer. LCD_CONTRAST_LEVEL(LCD_INITIAL_CONTRAST); //Set the LCD contrast level // Select asynchronous clock source, enable all COM pins and enable all // segment pins. LCDCRB = (1<<LCDCS) | (3<<LCDMUX0) | (7<<LCDPM0); // Set LCD prescaler to give a framerate of 32,0 Hz LCDFRR = (0<<LCDPS0) | (7<<LCDCD0); LCDCRA = (1<<LCDEN) | (1<<LCDAB); // Enable LCD and set low power waveform //Enable LCD start of frame interrupt LCDCRA |= (1<<LCDIE); gLCD_Update_Required = FALSE; } /***************************************************************************** * * Function name : LCD_WriteDigit(char c, char digit) * * Returns : None * * Parameters : Inputs * c: The symbol to be displayed in a LCD digit * digit: In which digit (0-5) the symbol should be displayed * Note: Digit 0 is the first used digit on the LCD, * i.e LCD digit 2 * * Purpose : Stores LCD control data in the LCD_displayData buffer. * (The LCD_displayData is latched in the LCD_SOF interrupt.) * *****************************************************************************/ void LCD_WriteDigit(char c, char digit) { unsigned int seg = 0x0000; // Holds the segment pattern char mask, nibble; volatile char *ptr; char i; if (digit > 5) // Skip if digit is illegal return; //Lookup character table for segmet data if ((c >= '*') && (c <= 'z')) { // c is a letter if (c >= 'a') // Convert to upper case c &= ~0x20; // if necessarry c -= '*'; //mt seg = LCD_character_table[c]; seg = (unsigned int) pgm_read_word(&LCD_character_table[(uint8_t)c]); } // Adjust mask according to LCD segment mapping if (digit & 0x01) mask = 0x0F; // Digit 1, 3, 5 else mask = 0xF0; // Digit 0, 2, 4 ptr = LCD_Data + (digit >> 1); // digit = {0,0,1,1,2,2} for (i = 0; i < 4; i++) { nibble = seg & 0x000F; seg >>= 4; if (digit & 0x01) nibble <<= 4; *ptr = (*ptr & mask) | nibble; ptr += 5; } } /***************************************************************************** * * Function name : LCD_AllSegments(unsigned char input) * * Returns : None * * Parameters : show - [TRUE;FALSE] * * Purpose : shows or hide all all LCD segments on the LCD * *****************************************************************************/ void LCD_AllSegments(char show) { unsigned char i; if (show) show = 0xFF; // Set/clear all bits in all LCD registers for (i=0; i < LCD_REGISTER_COUNT; i++) *(LCD_Data + i) = show; } /***************************************************************************** * * LCD Interrupt Routine * * Returns : None * * Parameters : None * * Purpose: Latch the LCD_displayData and Set LCD_status.updateComplete * *****************************************************************************/ SIGNAL(SIG_LCD) { static char LCD_timer = LCD_TIMER_SEED; char c; char c_flash; char flash; char EOL; unsigned char i; #ifndef REDUCED static char timeout_count; static char auto_joystick_count; #endif c_flash=0; // mt #ifndef REDUCED /**************** Button timeout for the button.c, START ****************/ if(!gButtonTimeout) { timeout_count++; if(timeout_count > 3) { gButtonTimeout = TRUE; timeout_count = 0; } } /**************** Button timeout for the button.c, END ******************/ /**************** Auto press joystick for the main.c, START *************/ if(gAutoPressJoystick == AUTO) { auto_joystick_count++; if(auto_joystick_count > 16) { gAutoPressJoystick = TRUE; auto_joystick_count = 15; } } else auto_joystick_count = 0; /**************** Auto press joystick for the main.c, END ***************/ #endif LCD_timer--; // Decreased every LCD frame if (gScrollMode) { // If we are in scroll mode, and the timer has expired, // we will update the LCD if (LCD_timer == 0) { if (gLCD_Start_Scroll_Timer == 0) { gLCD_Update_Required = TRUE; } else gLCD_Start_Scroll_Timer--; } } else { // if not scrolling, // disble LCD start of frame interrupt // cbi(LCDCRA, LCDIE); //DEBUG gScroll = 0; } EOL = FALSE; if (gLCD_Update_Required == TRUE) { // Duty cycle of flashing characters if (gFlashTimer < (LCD_FLASH_SEED >> 1)) flash = 0; else flash = 1; // Repeat for the six LCD characters for (i = 0; i < 6; i++) { if ((gScroll+i) >= 0 && (!EOL)) { // We have some visible characters c = gTextBuffer[i + gScroll]; c_flash = c & 0x80 ? 1 : 0; c = c & 0x7F; if (c == '\0') EOL = i+1; // End of character data } else c = ' '; // Check if this character is flashing if (c_flash && flash) LCD_WriteDigit(' ', i); else LCD_WriteDigit(c, i); } // Copy the segment buffer to the real segments for (i = 0; i < LCD_REGISTER_COUNT; i++) *(pLCDREG + i) = *(LCD_Data+i); // Handle colon if (gColon) *(pLCDREG + 8) = 0x01; else *(pLCDREG + 8) = 0x00; // If the text scrolled off the display, // we have to start over again. if (EOL == 1) gScroll = -6; else gScroll++; // No need to update anymore gLCD_Update_Required = FALSE; } // LCD_timer is used when scrolling text if (LCD_timer == 0) { /* if ((gScroll <= 0) || EOL) LCD_timer = LCD_TIMER_SEED/2; else*/ LCD_timer = LCD_TIMER_SEED; } // gFlashTimer is used when flashing characters if (gFlashTimer == LCD_FLASH_SEED) gFlashTimer= 0; else gFlashTimer++; }
LCD_functions.c
//***************************************************************************** // // File........: LCD_functions.c // // Author(s)...: ATMEL Norway // // Target(s)...: ATmega169 // // Compiler....: AVR-GCC 3.3.1; avr-libc 1.0 // // Description.: Additional LCD functions, scrolling text and write data // // Revisions...: 1.0 // // YYYYMMDD - VER. - COMMENT - SIGN. // // 20021015 - 1.0 - Created - LHM // 20030116 - 2.0 - Code adapted to AVR Butterflyup - KS // 20031009 port to avr-gcc/avr-libc - M.Thomas // //***************************************************************************** #define REDUCED // Include files #include <avr/io.h> #include <avr/pgmspace.h> #include <inttypes.h> #include "LCD_driver.h" #include "LCD_functions.h" #ifndef REDUCED #include "BCD.h" // mt only for KEY_* and ST_OPTIONS_DISPLAY* definitions: #include "main.h" #endif #define FALSE 0 #define TRUE (!FALSE) // mt char CONTRAST = LCD_INITIAL_CONTRAST; uint8_t CONTRAST = LCD_INITIAL_CONTRAST; // Start-up delay before scrolling a string over the LCD. "LCD_driver.c" extern char gLCD_Start_Scroll_Timer; /**************************************************************************** * * Function name : LCD_puts_f * * Returns : None * * Parameters : pFlashStr: Pointer to the string in flash * scrollmode: Not in use * * Purpose : Writes a string stored in flash to the LCD * *****************************************************************************/ // mt void LCD_puts_f(char __flash *pFlashStr, char scrollmode) void LCD_puts_f(const char *pFlashStr, char scrollmode) { // char i; uint8_t i; while (gLCD_Update_Required); // Wait for access to buffer // mt: for (i = 0; pFlashStr[i] && i < TEXTBUFFER_SIZE; i++) for (i = 0; (const char)(pgm_read_byte(&pFlashStr[i])) && i < TEXTBUFFER_SIZE; i++) { // mt: gTextBuffer[i] = pFlashStr[i]; gTextBuffer[i] = pgm_read_byte(&pFlashStr[i]); } gTextBuffer[i] = '\0'; if (i > 6) { gScrollMode = 1; // Scroll if text is longer than display size gScroll = 0; gLCD_Start_Scroll_Timer = 3; //Start-up delay before scrolling the text } else { gScrollMode = 0; gScroll = 0; } gLCD_Update_Required = 1; } /**************************************************************************** * * Function name : LCD_puts * * Returns : None * * Parameters : pStr: Pointer to the string * scrollmode: Not in use * * Purpose : Writes a string to the LCD * *****************************************************************************/ void LCD_puts(char *pStr, char scrollmode) { uint8_t i; // char i; while (gLCD_Update_Required); // Wait for access to buffer for (i = 0; pStr[i] && i < TEXTBUFFER_SIZE; i++) { gTextBuffer[i] = pStr[i]; } gTextBuffer[i] = '\0'; if (i > 6) { gScrollMode = 1; // Scroll if text is longer than display size gScroll = 0; gLCD_Start_Scroll_Timer = 3; //Start-up delay before scrolling the text } else { gScrollMode = 0; gScroll = 0; } gLCD_Update_Required = 1; } /**************************************************************************** * * Function name : LCD_putc * * Returns : None * * Parameters : digit: Which digit to write on the LCD * character: Character to write * * Purpose : Writes a character to the LCD * *****************************************************************************/ // mt void LCD_putc(char digit, char character) void LCD_putc(uint8_t digit, char character) { if (digit < TEXTBUFFER_SIZE) gTextBuffer[digit] = character; } /**************************************************************************** * * Function name : LCD_Clear * * Returns : None * * Parameters : None * * Purpose : Clear the LCD * *****************************************************************************/ void LCD_Clear(void) { uint8_t i; // char i; for (i=0; i<TEXTBUFFER_SIZE; i++) gTextBuffer[i] = ' '; } /**************************************************************************** * * Function name : LCD_Colon * * Returns : None * * Parameters : show: Enables the colon if TRUE, disable if FALSE * * Purpose : Enable/disable colons on the LCD * *****************************************************************************/ void LCD_Colon(char show) { gColon = show; } /**************************************************************************** * * Function name : LCD_UpdateRequired * * Returns : None * * Parameters : update: TRUE/FALSE * scrollmode: not in use * * Purpose : Tells the LCD that there is new data to be presented * *****************************************************************************/ void LCD_UpdateRequired(char update, char scrollmode) { while (gLCD_Update_Required); gScrollMode = scrollmode; gScroll = 0; gLCD_Update_Required = update; } /**************************************************************************** * * Function name : LCD_FlashReset * * Returns : None * * Parameters : None * * Purpose : This function resets the blinking cycle of a flashing digit * *****************************************************************************/ void LCD_FlashReset(void) { gFlashTimer = 0; } #ifndef REDUCED /**************************************************************************** * * Function name : SetContrast * * Returns : char ST_state (to the state-machine) * * Parameters : char input (from joystick) * * Purpose : Adjust the LCD contrast * *****************************************************************************/ char SetContrast(char input) { static char enter = 1; char CH, CL; if (enter) { LCD_Clear(); enter = 0; } CH = CHAR2BCD2(CONTRAST); CL = (CH & 0x0F) + '0'; CH = (CH >> 4) + '0'; LCD_putc(0, 'C'); LCD_putc(1, 'T'); LCD_putc(2, 'R'); LCD_putc(3, ' '); LCD_putc(4, CH); LCD_putc(5, CL); LCD_UpdateRequired(TRUE, 0); if (input == KEY_PLUS) CONTRAST++; else if (input == KEY_MINUS) CONTRAST--; if (CONTRAST == 255) CONTRAST = 0; if (CONTRAST > 15) CONTRAST = 15; LCD_CONTRAST_LEVEL(CONTRAST); if (input == KEY_ENTER) { enter = 1; return ST_OPTIONS_DISPLAY_CONTRAST; } return ST_OPTIONS_DISPLAY_CONTRAST_FUNC; } #endif // REDUCED
main.c
/* 《AVR专题精选》随书例程 3.通信接口使用技巧 项目:使用USI作为主I2C接口 文件:main.c 说明:主程序文件. 在AVR Bufferfly上演示USI做主I2C接口用法 控制EEPROM 24AA00 按键: 上 数据加 下 数据减 左 读取数据 右 写数据 中 随机数据 作者:邵子扬 时间:2012年12月17日 */ #include <avr/io.h> #include <avr/interrupt.h> #include <avr/pgmspace.h> #include <inttypes.h> #include <stdio.h> // 系统时钟频率 #define F_CPU 1000000UL #include <util/delay.h> #include "LCD_functions.h" #include "LCD_driver.h" #include "macromcu.h" // I2C 接口端口定义 #define SDA E, 5 #define SCL E, 4 // I2C 信号定义 #define I2C_MASTER 0 #define I2C_SLAVE 1 #define I2C_ACK 0 #define I2C_NAK 1 /* 函数说明: I2C初始化 参数说明: mode: b7654321: not use b0: 0 master, 1 slave */ void I2C_init(char mode, char speed) { // I2C 模式 // Master or Slave if(mode)// Slave { } else // master { PINSET(SDA); // Enable pullup on SDA, to set high as released state. PINSET(SCL); // Enable pullup on SCL, to set high as released state. PINDIR(SDA, PIN_OUTPUT); // Enable SDA as output. PINDIR(SCL, PIN_OUTPUT); // Enable SCL as output. USIDR = 0xFF; // Preload dataregister with "released level" data. USICR = (0<<USISIE)|(0<<USIOIE)| // Disable Interrupts. (1<<USIWM1)|(0<<USIWM0)| // Set USI in Two-wire mode. (1<<USICS1)|(0<<USICS0)|(1<<USICLK)| // Software stobe as counter clock source (0<<USITC); USISR = (1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)| // Clear flags, (0x0<<USICNT0); // and reset counter. } } // Prepare register value to: Clear flags, and // set USI to shift 8 bits i.e. count 16 clock edges. #define tempUSISR_8bit (1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|(0x0<<USICNT0) // Prepare register value to: Clear flags, and // set USI to shift 1 bit i.e. count 2 clock edges. #define tempUSISR_1bit (1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|(0xE<<USICNT0) #define TWI_READ_BIT 0 // Bit position for R/W bit in "address byte". #define TWI_ADR_BITS 1 // Bit position for LSB of the slave address bits in the init byte. #define TWI_NACK_BIT 0 // Bit position for (N)ACK bit. // USI 接口发送数据 unsigned char USI_TWI_Master_Transfer(unsigned char temp) { USISR = temp; temp = (0<<USISIE)|(0<<USIOIE)| // Interrupts disabled (1<<USIWM1)|(0<<USIWM0)| // Set USI in Two-wire mode. (1<<USICS1)|(0<<USICS0)|(1<<USICLK)| // Software clock strobe as source. (1<<USITC); // Toggle Clock Port. do { _delay_us(5); USICR = temp; // Generate positve SCL edge. while(!PININ(SCL)); // Wait for SCL to go high. _delay_us(5); USICR = temp; // Generate negative SCL edge. }while( !(USISR & (1<<USIOIF)) ); // Check for transfer complete. _delay_us(5); temp = USIDR; // Read out data. USIDR = 0xFF; // Release SDA. PINDIR(SDA, PIN_OUTPUT); // Enable SDA as output. return temp; // Return the data from the USIDR } // I2C 写一个字节 unsigned char I2C_Master_WriteByte(unsigned char dat) { PINCLR(SCL); // Pull SCL LOW. USIDR = dat; // Setup data. USI_TWI_Master_Transfer( tempUSISR_8bit ); // Send 8 bits on bus. /* Clock and verify (N)ACK from slave */ PINDIR(SDA, PIN_INPUT); // Enable SDA as input. if( USI_TWI_Master_Transfer( tempUSISR_1bit ) & (1<<TWI_NACK_BIT) ) return 1; else return 0; } // I2C 读取一个字节 unsigned char I2C_Master_ReadByte() { PINDIR(SDA, PIN_INPUT); return USI_TWI_Master_Transfer(tempUSISR_8bit); } // I2C 发送ACK信号 void I2C_Master_ACK(char ack) { if(ack == I2C_ACK) { USIDR = 0x00; } else { USIDR = 0xFF; } USI_TWI_Master_Transfer( tempUSISR_1bit ); // Generate ACK/NACK. } // I2C 起始信号 void I2C_start() { PINSET(SCL); // Release SCL. while(!PININ(SCL)); // Verify that SCL becomes high. _delay_us(5); PINCLR(SDA); // Force SDA LOW. _delay_us(5); PINCLR(SCL); // Pull SCL LOW. PINSET(SDA); // Release SDA. } // I2C 停止信号 void I2C_stop() { PINCLR(SDA); // Pull SDA low. PINSET(SCL); // Release SCL. while(!PININ(SCL)); // Wait for SCL to go high. _delay_us(5); PINSET(SDA); // Release SDA. _delay_us(5); } // 按键掩码 #define PINB_MASK ((1<<PINB4)|(1<<PINB6)|(1<<PINB7)) #define PINE_MASK ((1<<PINE2)|(1<<PINE3)) // 读取 AVR Butterfly 按键 unsigned char getkey() { unsigned char t; t = (~PINB) & PINB_MASK; t |= (~PINE) & PINE_MASK; return t; } unsigned char dat = 0, cnt; char s[] = " 00"; // HEX 转换为字符 unsigned char hexchr(unsigned char dat) { if(dat > 15) return '0'; if(dat < 10) return dat + '0'; else return dat - 10 + 'A'; } // HEX 转换为字符串 void hexbuf(unsigned char dat, char *buf) { buf[0] = hexchr(dat/16); buf[1] = hexchr(dat%16); } // 读取EEPROM地址0数据 unsigned char ReadByte() { unsigned char t; I2C_start(); // 发送起始信号 I2C_Master_WriteByte(0xA0); // 发送设备地址 I2C_Master_WriteByte(0x00); // 发送地址 I2C_start(); // 发送起始信号 I2C_Master_WriteByte(0xA1); // 发送读取命令 t = I2C_Master_ReadByte(); // 读取数据 I2C_Master_ACK(I2C_NAK); // 发送NAK信号 I2C_stop(); // 发送停止信号 return t; } // 写入数据到EEPROM地址0 void WriteByte(unsigned char dat) { I2C_start(); // 发送起始信号 I2C_Master_WriteByte(0xA0); // 发送设备地址 I2C_Master_WriteByte(0x00); // 发送地址 I2C_Master_WriteByte(dat); // 写入数据 I2C_stop(); // 发送停止信号 } // 主程序 int main() { // IO 初始化 PINDIR(SCL, PIN_OUTPUT); PINDIR(SDA, PIN_OUTPUT); PORTB |= PINB_MASK; PORTE |= PINE_MASK; // I2C 初始化 I2C_init(0, 0); // AVR Butterfly LCD初始化 LCD_Init(); // 开中断 sei(); // 显示地址和数据 hexbuf(dat, s+4); LCD_puts(s, 0); while(1) { _delay_ms(200); // 延时 cnt++; if(getkey()) // 读取按键 { switch(getkey()) { case 0x40://上, 数据递增 dat++; s[0] = ' '; break; case 0x80://下, 数据递减 dat--; s[0] = ' '; break; case 0x04://左, 读取数据 s[0] = 'R'; dat = ReadByte(); break; case 0x08://右, 写入数据 s[0] = 'W'; WriteByte(dat); break; case 0x10://中, 随机数据 //dat = ReadStatus(); //hexbuf(dat, s+2); dat = cnt; break; } hexbuf(dat, s+4); // 更新显示 LCD_puts(s, 0); } } return 0; }
仿真
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。