做过AVR开发的人,一般都会选择Keil或者IAR作为开发工具,当然也一定会有使用Microchip Studio或者MPLAB X IDE的。当我们使用AVR连接外部器件(比如LCD1602、27C64)的时候,需要编写驱动函数。这些函数要么自己从头编写,要么借鉴别人做好的源代码,并进行适当的修改后引入自己的工程中。
现在,我非常高兴为大家介绍一款专门用于开发AVR的、使用Pascal语言的开发工具----mikroPascal Pro ForAVR。那么这款开发工具有什么特点和优势呢?它提供了丰富的软件库,有了这些软件库,你就不需要专门去编写外部器件的驱动程序了,直接拿来用就行。比如我们想使用LCD1602作为显示部件,那么好你按照库函数的要求定义好LCD1602的IO接口,然后在程序中,直接调用库函数就可以了,不需要一行一行地编写具体的驱动代码。
这款软件的安装过程我就不多说了,对于搞开发的人来说,这简直就是小菜一碟,嘿嘿。下面我举例说明用mikroPascal Pro for AVR开发的过程。在进行开发之前,我们先做一下电路的总体设计,直接上电路图。
电路中使用PCF8583时钟芯片,PCF8583是串行总线扩展方式的实时时钟器件。电路中我们使用PC0和PC1连接PCF8583的SCL和SDA。使用LCD1602作为显示器件,连接到Mega16的PD口的一些IO,使用4位数据通讯模式。PA0作为ADC使用。
事实上,看到这个电路图,我们在心里是不是就已经想:我们需要编写PD口连接LCD的程序,包括LCD初始化函数、读写数据函数;需要编写ADC处理用的函数;需要编写PCF8583的初始化函数、数据读写函数、I2C总线的必要处理函数等。没错,如果使用普通开发工具,这些函数我们必须要编写。但是,如果我们使用的是mikroPascal,嘿嘿,这些函数我们都不需要做了。废话不多说,看代码。
var seconds, minutes, hours, day, month, year : byte; // Global date/time variables
var adc_rd : word;
// I2C接口定义 Begin
var Soft_I2C_Scl_Output : sbit at PORTC0_bit;
Soft_I2C_Sda_Output : sbit at PORTC1_bit;
Soft_I2C_Scl_Input : sbit at PINC0_bit;
Soft_I2C_Sda_Input : sbit at PINC1_bit;
Soft_I2C_Scl_Direction : sbit at DDC0_bit;
Soft_I2C_Sda_Direction : sbit at DDC1_bit;
// I2C接口定义 End
// LCD接口定义 Begin
var LCD_RS : sbit at PORTD2_bit;
var LCD_EN : sbit at PORTD3_bit;
LCD_D4 : sbit at PORTD4_bit;
LCD_D5 : sbit at PORTD5_bit;
LCD_D6 : sbit at PORTD6_bit;
LCD_D7 : sbit at PORTD7_bit;
var LCD_RS_Direction : sbit at DDD2_bit;
LCD_EN_Direction : sbit at DDD3_bit;
LCD_D4_Direction : sbit at DDD4_bit;
LCD_D5_Direction : sbit at DDD5_bit;
LCD_D6_Direction : sbit at DDD6_bit;
LCD_D7_Direction : sbit at DDD7_bit;
// LCD接口定义 End
// 从PCF8583取得时间和日期
procedure Read_Time();
begin
Soft_I2C_Start(); // I2C启动信号
Soft_I2C_Write(0xA0); // PCF8583的物理地址:0xA0
Soft_I2C_Write(2); // 启动PCF8583
Soft_I2C_Start(); // I2C启动信号
Soft_I2C_Write(0xA1); // PCF8583的读操作地址:0xA1
seconds := Soft_I2C_Read(1); // 读取秒
minutes := Soft_I2C_Read(1); // 读取分
hours := Soft_I2C_Read(1); // 读取小时
day := Soft_I2C_Read(1); // 读取日期
month := Soft_I2C_Read(0); // 读取月份
Soft_I2C_Stop(); // I2C停止信号
end;
//格式化日期、时间
procedure Transform_Time() ;
begin
seconds := ((seconds and 0xF0) shr 4)*10 + (seconds and 0x0F); // Transform seconds
minutes := ((minutes and 0xF0) shr 4)*10 + (minutes and 0x0F); // Transform months
hours := ((hours and 0xF0) shr 4)*10 + (hours and 0x0F); // Transform hours
year := (day and 0xC0) shr 6; // Transform year
day := ((day and 0x30) shr 4)*10 + (day and 0x0F); // Transform day
month := ((month and 0x10) shr 4)*10 + (month and 0x0F); // Transform month
end;
//输出数据到LCD1602上显示
procedure Display_Time();
begin
// 显示日期
Lcd_Chr(1, 9, (day / 10) + 48); // Print tens digit of day variable
Lcd_Chr(1, 10, (day mod 10) + 48); // Print oness digit of day variable
Lcd_Chr(1, 6, (month / 10) + 48);
Lcd_Chr(1,7, (month mod 10) + 48);
// 显示时间
UART1_Write_Text('Time: ');
Lcd_Chr(2, 6, (hours / 10) + 48);
Lcd_Chr(2, 7, (hours mod 10) + 48);
UART1_Write(hours/10+48); UART1_Write(hours mod 10 + 48); UART1_Write(':');
Lcd_Chr(2, 9, (minutes / 10) + 48);
Lcd_Chr(2,10, (minutes mod 10) + 48);
UART1_Write(minutes/10+48); UART1_Write(minutes mod 10 + 48); UART1_Write(':');
Lcd_Chr(2,12, (seconds / 10) + 48);
Lcd_Chr(2,13, (seconds mod 10) + 48);
UART1_Write(seconds/10+48); UART1_Write(seconds mod 10 + 48); UART1_Write(' ');
// 显示ADC结果
Lcd_Chr(1,13,(adc_rd/1000) + 48);
Lcd_Chr(1,14,((adc_rd mod 1000)/100) + 48);
Lcd_Chr(1,15,(adc_rd mod 100)/10 + 48);
Lcd_Chr(1,16,(adc_rd mod 10) + 48);
// 串口输出adc数据
UART1_Write_Text('Volt: ');
UART1_Write((adc_rd/1000) + 48);
UART1_Write((adc_rd mod 1000)/100 + 48);
UART1_Write((adc_rd mod 100)/10 + 48);
UART1_Write((adc_rd mod 10) + 48);
UART1_Write(13);UART1_Write(10);
end;
// 系统初始化
procedure Init_Main();
begin
UART1_Init(9600); // 初始化UART:n,8,1,9600
Delay_ms(100); // 等待UART初始化完成
UART1_Write_Text('Start'); // 输出Start
UART1_Write(13);UART1_Write(10); // 换行
Lcd_Init(); // 初始化LCD
Lcd_Cmd(_LCD_CLEAR); // 清除显示
Lcd_Cmd(_LCD_CURSOR_OFF); // 关闭光标
LCD_Out(1,1,'Date:'); // 位置(1,1)显示Date:
LCD_Chr(1,8,'-'); // 位置(1,8)显示-
LCD_Out(2,1,'Time:'); // 位置(2,1)显示Time:
LCD_Chr(2,8,':'); // 位置(2,8)显示:
LCD_Chr(2,11,':'); // 位置(2,11)显示:
LCD_Out(1,12,'V'); // 位置(1,12)显示V
Soft_I2C_Init(); // Initialize Soft I2C communication
end;
//----------------- Main procedure
begin
Init_Main(); // 系统初始化
while TRUE do // 主循环
begin
Read_Time(); // 从PCF8583取得时间和日期
Transform_Time(); // 格式化日期、时间
adc_rd := ADC_Read(0); // 获取ADC数据,这个数据将作为EEPROM的地址来使用
Display_Time(); // 显示数据
if (seconds = 0) then // 秒=0时,数据写入eeprom,eeprom的地址由ADC的数值定
EEPROM_Write(minutes,adc_rd/4); // Write some data at address
delay_ms(1000);
end;
end.
代码中包含注释,相信大家都能看懂。
下面我们使用mikroPascal建立一个新的工程,然后把这些代码拷贝进去。
打开mikroPascal
新建一个mega16的standard工程
选择Device Name选择为Mega16,Device clock设置为1.000000MHz。
Next
选择Yes,建立工程目录
继续“Next”
选择“Include All(Default)”,包含所有库,选择“Finish”
把“program MyProject;”这行后面的代码替换为之前的代码并执行编译。
没有错误。嘿嘿,是不是很奇怪?代码里用到的一些函数,我们并没有编写啊,怎么不报错呢?
注意右边区域中那个“Library Manager”,我们选择激活它。
看到了吗?所有库支持的包,都被勾选了。这是因为在建立工程的时候,我们选择了“Include All(Default)”这个选项。
事实上我们的工程只需要选择以下几个就可以了:ADC,Conversions,EEPROM,Lcd,Lcd_Constants,Software_I2C,String,UART。
因为工程中用到Lcd1602显示,软件实现I2C,ADC转换,串口通讯。
接下来,我们把编译生成的HEX文件关联到Proteu中Mega16器件上运行一下试试看
调节滑动电阻器,可以看到Lcd右上角数值的变化,以及虚拟串口输出的变化
成功了!是不是很爽?库函数替我们做了很多工作,我们需要做的就是把库函数用到的接口声明一下而已。
让我们看看库函数的帮助说明吧,以Lcd_Init为例:
展开库函数管理中的Lcd项目
双击“Lcd_Init”
帮助说明中,包括函数用到的接口定义要求、示例程序,甚至怎么接线都明明白白地写出来了。
虽然是英文,但是作为程序员,应该没有问题吧。
这个开发工具怎么样?对于熟悉Pascal(Delphi)开发的程序员,是不是很容易上手了啊?
---------------------
作者:suncat0504
链接:https://bbs.21ic.com/icview-3204224-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。