ATMEGA16程序实例
ATmega16时钟(完整版)

ATmega16时钟以CV A VR为编译环境的带校时和音乐报时功能时钟的设计与实现////////////////////////////////////////////////源程序/////////////////////////////////////////////// #include <mega16.h>#define key_input PINC // 按键输入口#define key_mask 0b11000000 // 按键输入屏蔽码#define key_no 0#define key_k1 1#define key_k2 2#define key_state_0 0#define key_state_1 1#define key_state_2 2#define Max_note 32flash unsigned char music[Max_note] ={5,2,8,2,5,2,4,2,3,2,2,2,1,4,1,2,1,2,2,2,3,2,3,2,1,2,3,2,4,2,5,8};flash unsigned char led_7[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};flash unsigned char position[6]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf};flash unsigned char d[9] = {0,105,116,132,140,157,176,198,209};flash unsigned int t[9] = {0,956,865,759,716,638,568,506,470};unsigned int int_n;unsigned char note_n;unsigned char dis_buff[6]; // 显示缓冲区,存放要显示的6个字符的段码值unsigned char time[3],time_set[3]; // 时、分、秒计数和设置单元unsigned char clock_state = 6,return_time;unsigned char time_counter,key_stime_counter; // 时间计数单元,bit point_on,set_on,time_1s_ok,key_stime_ok;bit play_on;void display(void) // 6位LED数管动态扫描函数{static unsigned char posit=0;PORTC = 0xff;PORTA = led_7[dis_buff[posit]];if (set_on && (posit==clock_state)) PORTA= 0x00; // 校时闪烁if (point_on && (posit==2||posit==4)) PORTA |= 0x80; // 秒闪烁PORTC = position[posit];if (++posit >=6 ) posit = 0; // (3)}// Timer 0 比较匹配中断服务,2ms定时interrupt [TIM0_COMP] void timer0_comp_isr(void){display(); // LED扫描显示if (++key_stime_counter >=5){key_stime_counter = 0;key_stime_ok = 1; // 10ms到if (!(++time_counter % 25)) set_on = !set_on; // 设置校时闪烁标志if (time_counter >= 100){time_counter = 0;time_1s_ok = 1; // 1s到}}}// T/C1 比较匹配A中断服务interrupt [TIM1_COMPA] void timer1_compa_isr(void){if (!play_on){note_n = 0;int_n = 1;play_on = 1;}else{if (--int_n == 0){TCCR1B = 0x08;if (note_n < Max_note){OCR1A = t[music[note_n]];int_n = d[music[note_n]];note_n++;int_n = int_n * music[note_n];note_n++;TCCR1B = 0x09;}elseplay_on = 0;}}}void time_to_disbuffer(unsigned char *time) // 时钟时间送显示缓冲区函数{unsigned char i,j=0;for (i=0;i<=2;i++){dis_buff[j++] = time[i] % 10;dis_buff[j++] = time[i] / 10;}}unsigned char read_key(void){static unsigned char key_state = 0,key_press;unsigned char key_return = key_no;key_press = key_input & key_mask; // 读按键I/O电平switch (key_state){case key_state_0: // 按键初始态if (key_press != key_mask) key_state = key_state_1;break; // 键被按下,状态转换到键确认态case key_state_1: // 按键确认态if (key_press == (key_input & key_mask)){if (key_press == 0b01000000) key_return = key_k1;else if (key_press == 0b10000000) key_return = key_k2;key_state = key_state_2; // 状态转换到键释放态}elsekey_state = key_state_0; // 按键已抬起,转换到按键初始态break;case key_state_2:if (key_press == key_mask) key_state = key_state_0;break; //按键已释放,转换到按键初始态}return key_return;}void main(void){unsigned char key_temp,i;DDRA=0xFF; // LED段码输出PORTC=0xFF;DDRC=0x3F; // LED位控输出DDRD=0x20; // PD5音乐播放输出// T/C0初始化OCR0 = 0xF9; // OCR0 = 0xF9(249),(249+1)/125=2msTCCR0 = 0x0A; // 内部时钟,8分频(1M/8=125KHz),CTC模式// T/C1初始化TCCR1A=0x40;TCCR1B=0x08;TIMSK = 0x12; // 允许T/C1比较匹配A中断,允许T/C0比较匹配中断time[2] = 23; time[1] = 58; time[0] = 55; // 设时间初值23:58:55#asm("sei") // 开放全局中断while (1){if (time_1s_ok) // 1秒到{time_1s_ok = 0;point_on = ~point_on; // 秒闪烁标志if (++time[0] >= 60) // 秒加1,以下为时间调整{time[0] = 0;if (!play_on) TCCR1B = 0x09; // 1分钟到,播放音乐if (++time[1] >= 60){time[1] = 0;if (++time[2] >= 24) time[2] = 0;}}if ((++return_time >= 20) && (clock_state != 6)) clock_state = 6;if (clock_state == 6) time_to_disbuffer(time);}if (key_stime_ok) // 10ms到,键处理{key_stime_ok = 0;key_temp = read_key(); // 调用按键接口程序if (key_temp) // 确认有键按下{return_time = 0;if (key_temp == key_k1) // K1键按下,状态转换{if (++clock_state >= 7) clock_state = 0;if (clock_state == 0){for (i=0;i<=2;i++) time_set[i] = 0;time_to_disbuffer(time_set);}if (clock_state == 6){for (i=0;i<=2;i++) time[i] = time_set[i];time_to_disbuffer(time);}}if ((clock_state != 6) && (key_temp == key_k2)) // K2键按下{if (clock_state%2) time_set[clock_state/2] += 10;else{if ((time_set[clock_state/2] % 10) == 9)time_set[clock_state/2] -= 9;elsetime_set[clock_state/2]+=1;}if (time_set[0] >= 60) time_set[0]-= 60; // 以下设置时间调整if (time_set[1] >= 60) time_set[1]-= 60;if (time_set[2] >= 24) time_set[2]-= 10;time_to_disbuffer(time_set); // 设置时间送显示缓存}}}}}。
ATmega16的DS18B20测温程序

unsigned char errTime=0;//用于循环计数
DQ_OUT;//先设置成输出 DQ_CLR;//总线拉低
Delay_Us(500);//保持500us(最小为480us,最大为960us) DQ_IN;//1 _NOP(); while(DQ_R)//探测 IO 引上是上升沿 {
uchar i; for(i=0;i<8;i++)//1个字节有8位,1位1位的传输
{ DQ_OUT;//先设置成输出 DQ_CLR;//总线拉低 Delay_Us(10);//按照写1时序,在15us 中完成所以延时10us if(value&0x01)//判断此时写入的值是1还是0 { DQ_SET;//如果是1,总线拉高,使得18B20能采样 } else DQ_CLR; Delay_Us(100);//如果是0(低电平)就不用管,继续延时(15+15+30=60us,100us 足够) DQ_SET;//释放总线 value=value>>1;//每次传输完后移位 } } uint ds18b20_read_byte(void)//18B20读一个字节的程序 { uint i,value;
for(i=0;i<8;i++) {
value=value>>1;//移位,最后一次读正好是最高位 DQ_OUT;//先设置成输出 DQ_CLR;//总线拉低 Delay_Us(10);//>1us,<15us 控制器读1时序 DQ_SET;//总线释放准备采样 DQ_IN;//采样,设置成输入 if(DQ_R)//如果读到的值是1 { value|=0x80;//从低位开始读取 } Delay_Us(50);//>45us } return value; } //读取温度值先读取暂存器的值在进行温度转换否则会意外出错 unsigned int readTempDS18B20(void) {
atmega16单片机c语言程序设计经典实例

atmega16单片机c语言程序设计经典实例中括号在C语言中用于表示数组、结构体、联合体和枚举类型等的定义和使用。
在ATmega16单片机的C语言程序设计中,我们经常会用到数组和结构体,因此本文将以中括号为主题,详细介绍ATmega16单片机上C语言程序设计的经典实例,包括数组的定义和使用、结构体的定义和使用、联合体的定义和使用以及枚举类型的定义和使用。
一、数组的定义和使用数组是一种用于存储一组相同类型的数据项的集合。
在ATmega16单片机上,我们可以使用数组来存储和操作多个引脚的状态、多个传感器的数据等。
1. 数组的定义在C语言中,可以使用方括号来定义一个数组。
下面是一个例子,定义了一个长度为5的整型数组:int array[5];其中,int表示数组的元素类型,array为数组名,[5]表示数组的长度。
2. 数组的初始化数组可以在定义的同时进行初始化。
例如,可以使用大括号将数组的元素初始化为指定的值。
下面是一个例子,将数组的元素初始化为1、2、3、4、5:int array[5] = {1, 2, 3, 4, 5};3. 数组的访问可以使用下标(在中括号内)来访问数组的元素。
数组的下标从0开始,最大值为数组长度减1。
下面是一个例子,访问数组的第一个元素和最后一个元素:int firstElement = array[0];int lastElement = array[4];可以使用循环结构来遍历数组的所有元素:for (int i = 0; i < 5; i++) {访问数组的第i个元素int element = array[i];其他操作}二、结构体的定义和使用结构体是一种可以存储不同类型数据项的数据结构。
在ATmega16单片机上,结构体可以用于存储和操作多个相关的数据项,比如传感器的位置和数值等。
1. 结构体的定义在C语言中,可以使用关键字struct来定义结构体。
下面是一个例子,定义了一个包含姓名和年龄的结构体:struct Person {char name[20];int age;};其中,Person为结构体名,name和age为结构体的成员。
ATMEGA16读写iic(TWI)(24c02)C语言程序

ATMEGA16 读写iic(24c02) C 语言程序测试通过nclude <iom16v.h>#i nclude "I2C.h"#in clude "1602.h"#in clude "delay.h"/*通过AVR往I IC写数据,并通过串口把数据读出显示出来*///===============================================================void UAR_i nit(void) //UART 初始化{ DDRD = 0x02;PORTD = 0x00;UCSRA = 0x02; /* 无倍速*/UCSRB = 0x18; /*允许接收和发送*/U(SRC= 0x06; 1*8位数据,1位停止位,无校验*/UBRRH = 0x00;UBRRL = 12; /*9600*/}//===============================================================void USART_TXD(float data) // 发送采用查询方式{while( !(UCSRA & BIT(UDRE)));UDR=data;while( !(UCSRA & BIT(TXC )));UCSRA|=BIT(TXC);}void mai n(void){un sig ned char i;// LCDinit();uart_i ni t();//TART 初始化SEI(); // 全局中断使能while(1){/*I2C_Write('n',0x00); I2C_Write('c',0x01); I2C_Write('e',0x02);I2C_Write('p',0x03); I2C_Write('u',0x04);*/ i=I2C_Read(0x00); //LCD_write_char(0,0,i); USART_TXD(i); i=I2C_Read(0x01);//LCD_write_data(i); USART_TXD(i); i=I2C_Read(0x02); //LCD_write_data(i); USART_TXD(i);i=I2C_Read(0x03); //LCD_write_data(i); USART_TXD(i); i=I2C_Read(0x04); //LCD_write_data(i); USART_TXD(i);}}/* 上面上主函数部分*/#include <macros.h>#include "delay.h"//I2C 状态定义//MT 主方式传输MR 主方式接受#define START 0x08#define RE_START 0x10#define MT_SLA_ACK 0x18 #define MT_SLA_NOACK 0x20 #define MT_DATA_ACK 0x28 #defineMT_DATA_NOACK 0x30 #define MR_SLA_ACK 0x40 #define MR_SLA_NOACK 0x48 #define MR_DATA_ACK 0x50 #define MR_DATA_NOACK 0x58#define RD_DEVICE_ADDR 0xA1 // 前4位器件固定,后三位看连线,最后1位是读写指令位#define WD_DEVICE_ADDR 0xA0//常用TWI操作(主模式写和读)#define Start() (TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)) // 启动I2C #define Stop()(TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)) // 停止I2C #define Wait() {while(!(TWCR&(1<<TWINT)));} // 等待中断发生#define TestAck() (TWSR&0xf8) // 观察返回状态#define SetAck (TWCR|=(1<<TWEA)) // 做出ACK应答#define SetNoAck (TWCR&=~(1<<TWEA)) // 做出Not Ack 应答#define Twi() (TWCR=(1<<TWINT)|(1<<TWEN)) // 启动I2C#define Write8Bit(x) {TWDR=(x);TWCR=(1<<TWINT)|(1<<TWEN);} // 写数据到TWDRunsigned char I2C_Write(unsigned char Wdata,unsigned char RegAddress); unsigned charI2C_Read(unsigned RegAddress);/*********************************************I2C 总线写一个字节返回0: 写成功返回1: 写失败**********************************************/unsigned char I2C_Write(unsigned char Wdata,unsigned char RegAddress){Start(); //I2C 启动Wait();if(TestAck()!=START)return 1; //ACKWrite8Bit(WD_DEVICE_ADDR); // 写I2C 从器件地址和写方式Wait(); if(TestAck()!=MT_SLA_ACK) return 1; //ACKWrite8Bit(RegAddress); // 写器件相应寄存器地址Wait();if(TestAck()!=MT_DATA_ACK)return 1; //ACKWrite8Bit(Wdata); // 写数据到器件相应寄存器Wait();if(TestAck()!=MT_DATA_ACK)return 1; //ACKStop(); //I2C 停止delay_nms(10); // 延时return 0;}/*********************************************I2C 总线读一个字节返回0: 读成功返回1: 读失败**********************************************/unsigned char I2C_Read(unsigned RegAddress){ unsigned char temp;Start();//I2C 启动Wait();if (TestAck()!=START) return 1; //ACKWrite8Bit(WD_DEVICE_ADDR); // 写I2C 从器件地址和写方式Wait(); if (TestAck()!=MT_SLA_ACK) return 1; //ACKWrite8Bit(RegAddress); // 写器件相应寄存器地址Wait();if (TestAck()!=MT_DATA_ACK) return 1;Start(); //I2C 重新启动Wait();if (TestAck()!=RE_START) return 1;Write8Bit(RD_DEVICE_ADDR); // 写I2C 从器件地址和读方式Wait(); if(TestAck()!=MR_SLA_ACK)return 1; //ACKTwi(); // 启动主I2C 读方式Wait(); if(TestAck()!=MR_DATA_NOACK) return 1; //ACKtemp=TWDR;// 读取I2C 接收数据Stop();//l2C 停止return temp;}/*以上是IlC.h头文件部分,需要对照技术文档好好研究*/延时函数编译器:I CC-AVR V6.31A 日期:2005-11-24 20:29:57 目标芯片:M16 时钟:8.0000M Hz作者:arche ng504------------------------------------------------- */#ifndef __delay_h#defi ne __delay_hvoid delay_ nus(un sig ned int n);void delay_ nms(un sig ned int n);void delay_1us(void);void delay_1ms(void);void delay_1us(void) //1us 延时函数{asm( "n op");}void delay_ nus(un sig ned int n) 〃N us 延时函数{un sig ned in t i=0;for (i=0;i <n ;i++)delay_1us();}void delay_1ms(void) //1ms 延时函数{un sig ned in t i;for (i=0;i<1140;i++);}void delay_ nms(un sig ned int n) //N ms 延时函数{un sig ned in t i=0;for (i=0;i <n ;i++)delay_1ms();}#en dif/*以上是delay.h 部分,再加上IIC中自带的iom16v.h和macros.h就可以编译通过*//*注意点:本程序在实验板ATMEGA1上测试通过,在示波器把SCL, SDA信号线有数据,移值到自己电路上可以放心使用,在ATMEGA3上一样使用,本人24C02的A2, A1, A0都是接地,若地址不一样,在程序相应位置改一下就可以,串口上调试单片机的基础,所以它一定要会用*//*本程序调试软件环境是ICC6.31*/。
ATmega16串口程序-值得参考

// USART Transmitter buffer
#define TX_BUFFER_SIZE 16
volatile char tx_buffer[TX_BUFFER_SIZE];
volatile unsigned char tx_wr_index,tx_rd_index,tx_counter;
if (++rx_wr_index == RX_BUFFER_SIZE) //写指针指向下一个单元,并判断是否到了队列的尾部,(不表示接受缓冲区是否满!)
rx_wr_index=0; //到了尾部,则指向头部(构成环状)
if (++rx_counter == RX_BUFFER_SIZE) //队列中收到字符加1,并判断是否队列已满
{
rx_counter=0; // 队列满了,队列中收到字符个数为0,表示队列中所有以前的数据作废,因为最后的数据已经把最前边的数据覆盖了
rx_buffer_overflow=1; //置缓冲区溢出标志。在主程序中必要的地方需要判断该标志,以证明读到数据的完整性
put_s("Hello!");
put_s("这是一个简单的高速的串口驱动程序");
put_s("请你输入任意的字符,单片机将返回你输入的字符");
while (1)
{
put_c(get_c());
}
}
//Makefile,主要的几项,只是针对我这里的程序,要灵活运用哦
//usart.h
//常量定义
#define BAUDRATE 9600 //波特率
//#define F_CPU 4000000 //晶振频率4.0MHz
单片机片上开发方法(ATmega16为例)

在开始之前
设置ICC,使其配置成为可以开发ATmega16 的编译器环境
2014-11-12
43
设置你的ICC
Project Options…
2014-11-12
44
设置你的ICC
如图在Target标签中的Device Configuration里 选择ATmega16单片机,点击OK即可
2014-11-12
35
2014-11-12
36
在工程中建立一个LED.c文件
File Save As…
2014-11-12
37
在工程中建立一个LED.c文件
在刚建立的LED_test文件夹内保存成LED.c
2014-11-12
38
将LED.c添加到工程中
File (右击)Add File(s)…
LED灯闪烁程序解释
/*8MHz晶振下*/ //微秒级延时函数 void delay_us(unsigned int time) {do { time--; } while (time>1);} //毫秒级延时函数 void delay_ms(unsigned int time) {while(time!=0) { delay_us(1000); time--;}}
以后,我们可以 通过双击这个文 件运行ICC,可 不受其30天试用 期限制,但仅限 于自己学习,不 能用于其它用途!
2014-11-12
28
运行ICC
使用刚才的ICC.exe运行ICC7.13
2014-11-12
29
ICC的界面
2014-11-12
30
新建一个工程
Atmega16单片机实用程序

#define uint unsigned int #define SET_1(a,b) a|=bit(b) //將寄存器 a 的第 b 位置 1 #define CLR_0(a,b) a&=~bit(b) //將寄存器 a 的第 b 位清 0 #program date code:
const date[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0 X80,//共陽數據;
Atmega16 单片机实用程序
/************************************************ *********************
MCU: ATmega16 外部晶振: 8MHz 程序功能: 4*4 鍵盤識別,LED 七段數碼管顯示,密 碼功能模塊,直流電機正反轉控制
void delayms(int ms) { int i,j;
for(i=ms;i>0;i--) { for(j=1722;j>0;j 1722; }
/************************************************ ******************* 名稱:us 延時子程序 功能:延時指定的 us ************************************************* *******************/ void delayus(uchar us)
//interrupt process program void process()
{ int adcode=0; ADCSRA&=~BIT(ADIE); adcode=ADCL; adcode=(ADCH>3; y_address=y;
ADC实验 ATmega16

6.2模数转换的ADC实验 6.2.1、实例功能AVR的模数转换器ADC具有下列特点:110位精度;20.5LSB积分非线形误差3±2LSB的绝对精度;413µs~260µs的转换时间;5在最大精度下可达到每秒15kSPS的采样速率;68路可选的单端输入通道;77路差分输入通道;82路差分输入通道带有可选的10×和200×增益;9ADC转换结果的读取可设置为左端对齐(LEFT ADJUSTMENT);10ADC的电压输入范围0~Vcc;11可选择的内部2.56V的ADC参考电压源;12自由连续转换模式和单次转换模式;13ADC自动转换触发模式选择;14ADC转换完成中断;15休眠模式下的噪声抑制器(NOISE CANCELER)。
在本实例中,我们将编写程序实现将模数转换后获得的电压值通过单片机的串口发送到计算机,然后通过计算机上的串口助手显示测量的电压值。
本实例共有3个功能模块,分别描述如下:●单片机系统:使用单片机的串口实现将模数转换后获得的电压值通过串口发送到计算机。
●外围电路:RS232电平转换电路,DB9串行接口插座,模拟电压输入采集电路。
●软件程序:进一步熟悉单片机的串行通信,并掌握单片机的模数转换的方法。
6.2.2、器件和原理关于串行接口的原理已接单片机与计算机的串口的连接在上一实例中进行了描述,在本实例中不再重复。
本实例只介绍ATmega16单片机如何通过内置的模数转换模块采集外界输入的模拟电压。
1、ATmega16单片机的模数转换器ADC介绍由于单片机只能处理数字信号,所以外部的模拟信号量需要转变成数字量才能进一步的由单片机进行处理。
ATmega16内部集成有一个10位逐次比较(successive approximation)ADC电路。
因此使用AVR可以非常方便的处理输入的模拟信号量。
ATmega16的ADC与一个8通道的模拟多路选择器连接,能够对以PORTA作为ADC输入引脚的8路单端模拟输入电压进行采样,单端电压输入以0V(GND)为参考。