这里首先补充下IO口的中断,中断是通过PxIE,PxIES,PxIFG决定的,配置中断仍然要设置方向寄存器,上拉下拉使能寄存器,上拉下拉极性寄存器。
在这块芯片中有个COMPARE模块,这个模块就是个比较器而已。如图1.
图1 compare的结构图
这张图清楚表明了compare的结构和控制的方法。
作为一个比较器的话,首先要有同向输入端和反向输入端,同向输入端是通过CA0,CA1,CA2三位决定的,如果是000代表的是内部输入!剩下的那部分就是内部参考电压选择,CAEX是交换输入端,这样的话就会使输出CAOUT反转,CARSEL就是选择输入到参考电压输入到哪个端子,CAON是比较器是否打开,CAOUT是输出的值,这个不是管脚而是寄存器的值,CAF是输出滤波的禁用和使能控制端。程序如下:
void compare_init(void)
{
CACTL1 = 0x00;
CACTL2 = 0x00;
//CAPA = 0x00;
/* 选择参考电压为0.25V */
CACTL1_bit.CAREF1 = 0;
CACTL1_bit.CAREF0 = 1;
CACTL2 |= (4<<3);
CACTL2_bit.CAF = 1;
CACTL1_bit.CAON = 1;
}
注意:大家可以直接把这个模块理解为一个集成在MSP430内部的比较器,里面的控制器就是你要接的线的控制开关。画张比较器的图一一对比就比较好理解其功能了。
ADC10模块:
在这块芯片中有个ADC模块而且有四种模式,单通道单次,单通道连续,序列单次,序列连续,这里解释几个名词,什么是通道呢?直观上讲,我们配置好ADC后,每个管脚就是通道了;什么是序列?序列我说个简单的理解方式,就是一个通道就是包含一个元素的序列,多个通道就是一个多个元素的序列了;但是序列是怎么组织呢?在MSP430中序列的意思就是,从你要开始采集的通道开始,一个接一个的采集直道通道0,举个例子就是如果我们配置的是从通道4开始,那么它会转化完通道4接着转化通道3接着是通道2接着通道1接着通道0,这时如果设置的是单次那么就不转化了,如果是连续的话,它就会再次从通道4开始直到通道0转化结束,周而复始转化。同样我们学习ADC就要开他的结构图了,如图2。
图2
ADC转换需要参考电压,时钟,输入信号;我们就以这几个开始说明工作原理,再贴程序,参考电压是在上面的那块。
参考电压是通过内置的,为了适应不同环境,那么就有多个参考了,这时就要有选择的寄存器位了,因为只有两个就通过一个位来的REF_2.5(这里还有个附加功能就是输出这个参考电压,这是通过REFOUT位设置的,输出的方式又通过REFBURST实现是连续还是只在采样时输出,当然还需要设置IO口的功能了,一般用不到这里就不说了),有了这些后,我们到底是选择最小,最大参考电压呢?这些SREF[0:3]设置的(这三位在寄存器ADC10CTL0的15-13位)。
AD转化是需要时间的所以要有采样保持位通过ADC10SHTX[0:1](ADC10CTL0寄存器的12-12位),时钟是通过SHSX选择的,这张图里面的同步sync是不存在的,MSP430只有ENC控制使能和禁止位,时钟分频因子,好了配置好之后ADC10的时钟ADC10CLK就确定了。
输入信号,就是配置IO输入引脚了,这些就是通过ADC10AEx选择的,这时候的IO口就是AD输入了,大家可以看看上篇的管脚第二功能选择。
为了存下ADC10的数据呢,就需要一个寄存器保存这个值,这个模块中设计了一个ADC10MEM,这个就是数据的读取地方,具体就是当结果转化完ADC10模块就把数据放到这个寄存器中,但我们什么时候知道数据完成了呢?又需要一个标志位了,这个标志位就是ADC10IFG,这里提一下这个模块还提供了一个ADC10BUSY位用指示模块是否在转化,我们开始通过开始后检查这个位来读取,不过这个方法不大好,还是通过判断ADC10IFG比较好。
为了更好的控制ADC10就要有不同的模式了,也就是上面说的四种模式了,还有中断什么的,这些都和以前说的中断一样,打开中断使能。
程序如下
void ad10_scsc_init(unsigned char channel)
{
ADC10CTL0 |= (1<<13)|(2<<11)|(1<<6)|(1<<5)|(1<<3);
ADC10CTL1 |= (channel<<12)|(7<<5)|(3<<3);
ADC10AE0 |= (1<<0);
ADC10CTL0 |= (1<<4);
}
void ad10_start(void)
{
ADC10CTL0 |=(3<<0);
}
void ad10_scsc_read(unsigned short *ad_date)
{
while(ADC10CTL1&(1<<0));
*ad_date=ADC10MEM;
}
注意:这是个单通道单次的,也是我们经常使用的,因为初始化时一定不要打开转化,因为数据可能不是我们要的,我们需要在我们需要时再转化,转化是要在一条语句中置位ENC,ADC10SC,具体的原因就是设计这个模块的人知道了,呵呵,文档是怎么说的。这个是中断接受的程序,所以我没判断ADC10IFG,因为进中断肯定是ADC10IFG置位了,所以就没必要判断了。
好了,到此为止,ADC就介绍完了,这个芯片就差SPI模块了,但是这个模块不好使,觉得你还是自己模拟下时序吧,我模拟了一个IIC的希望对大家有益,下面我把IIC的程序贴上,这是验证过的,具体的IIC协议在下一篇文档中介绍下,并且说点书电知识。
#include "iic.h"
#include "io430.h"
#include "delay.h"
unsigned char g_iic_date;
#define IIC_CLK P1OUT_bit.P7
#define IIC_W_SDA P1OUT_bit.P6
#define IIC_R_SDA P1IN_bit.P6
void iic_reset(void)
{
P1OUT_bit.P6 = 0;
P1OUT_bit.P7 = 0;
P1DIR_bit.P6 = 0;
P1DIR_bit.P7 = 0;
P1REN_bit.P6 = 0;
P1REN_bit.P7 = 0;
P1SEL_bit.P6 = 0;
P1SEL_bit.P6 = 0;
P1SEL_bit.P7 = 0;
P1SEL2_bit.P6 = 0;
P1SEL2_bit.P7 = 0;
}
void iic_clk_init(void)
{
P1DIR_bit.P7 = 1;
P1OUT_bit.P7 = 0;
}
void iic_w_sda_init(void)
{
P1REN_bit.P6 = 0;
P1DIR_bit.P6 = 1;
P1OUT_bit.P6 = 1;
}
void iic_r_sda_init(void)
{
P1DIR_bit.P6 = 0;
P1REN_bit.P6 = 1;
P1OUT_bit.P6 = 1;
}
void iic_start(void)
{
IIC_CLK = 1;
delay(1);
IIC_W_SDA = 1;
delay(1);
IIC_W_SDA = 0;
delay(1);
}
void iic_send_date(unsigned char iic_byte)
{
unsigned char i_temp;
for(i_temp=0;i_temp<8;i_temp++)
{
IIC_CLK = 0;
delay(1);
if((iic_byte>>(7-i_temp))&0x01)
{
IIC_W_SDA = 1;
}
else
{
IIC_W_SDA = 0;
}
delay(1);
IIC_CLK = 1;
delay(1);
}
IIC_CLK=0;
delay(1);
}
void iic_read_date(unsigned char *iic_r_byte)
{
unsigned char i_temp;
unsigned char date_temp;
IIC_CLK=0;
;;;;;;;
for(i_temp=0;i_temp<8;i_temp++)
{
IIC_CLK = 0;
delay(1);
IIC_CLK = 1;
delay(1);
if(IIC_R_SDA!=0)
date_temp |= 1<<(7-i_temp);
else
date_temp |= 0<<(7-i_temp);
delay(1);
}
*iic_r_byte=date_temp;
IIC_CLK = 0;
delay(1);
}
void iic_response(void)
{
unsigned char i_temp=0;
IIC_CLK = 0;
delay(1);
IIC_CLK = 1;
delay(1);
while((IIC_R_SDA!=0)&&(i_temp<255))i_temp++;
IIC_CLK = 0;
delay(1);
}
void iic_stop(void)
{
IIC_W_SDA = 0;
delay(1);
IIC_CLK = 1;
delay(1);
IIC_W_SDA = 1;
delay(1);
IIC_CLK = 0;
delay(1);
}
void iic_start_write(void)
{
iic_clk_init();
delay(1);
iic_w_sda_init();
iic_start();
iic_send_date(0xa0);
iic_r_sda_init();
delay(1);
iic_response();
iic_w_sda_init();
iic_send_date(0xa0);
iic_r_sda_init();
delay(1);
iic_response();
iic_w_sda_init();
iic_send_date(0xa0);
iic_r_sda_init();
delay(1);
iic_response();
iic_w_sda_init();
iic_stop();
}
void iic_start_read(void)
{
iic_w_sda_init();
iic_start();
iic_send_date(0xa0);
iic_r_sda_init();
delay(1);
iic_response();
iic_w_sda_init();
iic_send_date(0xa0);
iic_r_sda_init();
delay(1);
iic_response();
iic_w_sda_init();
iic_start();
iic_send_date(0xa1);
iic_r_sda_init();
delay(1);
iic_response();
iic_read_date(&g_iic_date);
delay(1);
iic_w_sda_init();
iic_stop();
}
好了MSP430到此为止了,学习这块芯片我用了四天,其实只要有好的单片机基础完全可以学的很快,而且理解也很深的噢,这里也随便说说我读文档时理解的一个小知识点,这块芯片是统一寻址的,也就是寄存器和存储单元是统一编址的。