@floatsd
2016-01-02T12:38:04.000000Z
字数 23774
阅读 1069
CM4实验报告
范璐 自动化1302 201303080207
- 我觉得给那块板子拍照是件比较愚蠢的事情,主要是时间花的不值得,毕竟验收的时候已经看过了。而且,虽然每个模块的函数独立而且各司其职,但是主要是每次的①主函数和②中断向量中断优先级中断使能等中断相关③文件包含关系都要改一些东西。如果要依次再把之前的实验都做一遍,意味着要多次改整个的那个项目,修改东西往往比加东西要来的复杂和蛋疼。因为改东西有时候,改着改着,就不对了。出于以上担忧,我决定不拍板子跑程序的效果照片并对做了这项工作的同学报以崇高的敬意。
- 接触到的第一个例程是@zxk的例程是一件幸运的事,从一开始就养成了一些比较能够提高效率的编程习惯。@zxk的教学基本都是干货,在对每次要用的模块长什么样有个概念的前提下,他的讲解清晰易懂,并且会补充一些实用的细节,为快速入门之佳品,在此对助教表达感谢。
- 后几个实验难度其实比较大,但是学长已经做好了大部分工作,几乎相当于已经编写了一套库函数出来,我们只要使用即可,大大的减轻了实验难度和我们的工作量。
- 使用的在线编辑器基于markdown语言,很方便,就是没法空行或者打空格。导出PDF时的分页因此变得无法控制,丑的不忍直视。
- 把CCS安装好,熟悉CCS操作,编译界面
- 创建工程,开始学习TM4C1294软件开发过程
- 了解GPIO的概念,学会查找端口功能,调用GPIO库函数让LED跑起来
/*******************************************************************
* 函数: Clock_Init()
* 描述: 配置使能系统时钟
* 输入值:无
* 返回值:无
*****************************************************************/
void Clock_Init(){
SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |//外部时钟25MHz
SYSCTL_OSC_MAIN |//OSC时钟源选择主振荡器作为OSC
SYSCTL_USE_PLL |//采用锁相环PLL作为系统时钟源
SYSCTL_CFG_VCO_480), //压控振荡器频率480MHz
sysClock_Fr);//设定系统频率为sysClock_Fr
}
uint32_t SysCtlClockFreqSet(uint32_t ui32Config,uint32_t ui32SysClock);
这里ui32Config
表示时钟配置,例如外部时钟,是否使用PLL,时钟源设置等,它的其他可选项如下图: 信号 | 端口 | 信号 | 端口 |
---|---|---|---|
LED0 | PF1 | LED1 | PF2 |
LED2 | PF3 | LED3 | PL0 |
LED4 | PL1 | LED5 | PL2 |
LED6 | PL3 | LED7 | PL4 |
/*******************************************************************
* 函数: LED_Init()
* 描述: LED的配置及初始化
* 输入值:无
* 返回值:无
*****************************************************************/
void LED_Init()
{
//使能GPIOF和GPIOL模块
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL);
//将8盏LED配置为输出模式(GPIO管脚方向)
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE,GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
GPIOPinTypeGPIOOutput(GPIO_PORTL_BASE,GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4);
}
/*******************************************************************
* 函数: LED_ON(uint8_t NumLED)
* 描述: 点亮某一盏LED灯
* 输入值:uint8_t NumLED
* 返回值:无
*****************************************************************/
void LED_ON(uint8_t NumLED){
switch(NumLED){
case 0: GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_1,GPIO_PIN_1);break;
case 1: GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_2,GPIO_PIN_2);break;
case 2: GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_3,GPIO_PIN_3);break;
case 3: GPIOPinWrite(GPIO_PORTL_BASE,GPIO_PIN_0,GPIO_PIN_0);break;
case 4:GPIOPinWrite(GPIO_PORTL_BASE,GPIO_PIN_1,GPIO_PIN_1);break;
case 5: GPIOPinWrite(GPIO_PORTL_BASE,GPIO_PIN_2,GPIO_PIN_2);break;
case 6: GPIOPinWrite(GPIO_PORTL_BASE,GPIO_PIN_3,GPIO_PIN_3);break;
case 7: GPIOPinWrite(GPIO_PORTL_BASE,GPIO_PIN_4,GPIO_PIN_4);break;
default: ledclose();break; //让所有灯灭的一个函数
}}
/*******************************************************************
* 函数: LED_OFF(uint8_t NumLED)
* 描述: 不亮某一盏LED灯
* 输入值:uint8_t NumLED
* 返回值:无
*****************************************************************/
void LED_OFF(uint8_t NumLED){
switch(NumLED){
case 0: GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_1,0x00);break;
case 1: GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_2,0x00);break;
case 2: GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_3,0x00);break;
case 3: GPIOPinWrite(GPIO_PORTL_BASE,GPIO_PIN_0,0x00);break;
case 4: GPIOPinWrite(GPIO_PORTL_BASE,GPIO_PIN_1,0x00);break;
case 5: GPIOPinWrite(GPIO_PORTL_BASE,GPIO_PIN_2,0x00);break;
case 6: GPIOPinWrite(GPIO_PORTL_BASE,GPIO_PIN_3,0x00);break;
case 7: GPIOPinWrite(GPIO_PORTL_BASE,GPIO_PIN_4,0x00);break;
default: ledclose();break; //让所有等灭的一个函数
}}
/*******************************************************************
* 函数: Delay(uint32_t CountMs)
* 描述: 延时
* 输入值: uint32_t CountMs
* 返回值: 无
*****************************************************************/
void Delay(uint32_t CountMs){
SysCtlDelay(CountMs*sysClock_Fr/3000);
}
void GPIOPin Type ADC (uint32_t ui32Port, uint8_t ui8Pins)
void GPIOPin Type CAN (uint32_t ui32Port, uint8_t ui8Pins)
void GPIOPin Type CIR (uint32_t ui32Port, uint8_t ui8Pins)
void GPIOPin Type Comparator
void GPIOPin Type EPI
void GPIOPin Type Ethernet LED
void GPIOPin Type Ethernet MII
void GPIOPin Type GPIOInput
void GPIOPin Type GPIOOutput
- 熟悉和掌握矩阵式键盘的工作原理、电路设计和软件编程方法。
- 熟悉和掌握矩阵键盘的行列扫描法
信号 | 端口 | 信号 | 端口 |
---|---|---|---|
ROW1_IN | PP2 | COL1_OUT | PD1 |
ROW2_IN | PN3 | COL2_OUT | PH3 |
ROW3_IN | PN2 | COL3_OUT | PH2 |
ROW4_IN | PD0 | COL4_OUT | PM3 |
/*******************************************************************
* 函数: Toggle_Init()
* 描述: 配置使能矩阵按钮gpio口
* 输入值:无
* 返回值:无
*****************************************************************/
void Toggle_Init()
{
//使能引脚
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOH);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOM);
//输入配置
GPIOPinTypeGPIOInput(GPIOP, GPIO_PIN_2);
GPIOPinTypeGPIOInput(GPION, GPIO_PIN_2|GPIO_PIN_3);
GPIOPinTypeGPIOInput(GPIOD, GPIO_PIN_0);
//输出配置
GPIOPinTypeGPIOOutput(GPIOD, GPIO_PIN_1);
GPIOPinTypeGPIOOutput(GPIOH, GPIO_PIN_2|GPIO_PIN_3);
GPIOPinTypeGPIOOutput(GPIOM, GPIO_PIN_3);
//设置行都为高电平,列为低电平
R1h();
R2h();
R3h();
R4h();
C1l();
C2l();
C3l();
C4l();
}
/*******************************************************************
* 函数: Row_Scan()
* 描述: 扫描行或列返回电平被拉低的行/列
* 输入值:无
* 返回值:uint8_t
*****************************************************************/
uint8_t Row_Scan(){
uint8_t r0,r1,r2,r3;
r0 = GPIOPinRead(GPIOP, GPIO_PIN_2);
r1 = GPIOPinRead(GPION, GPIO_PIN_2);
r2 = GPIOPinRead(GPION, GPIO_PIN_3);
r3 = GPIOPinRead(GPIOD, GPIO_PIN_0);
if(r0==0x00){
return 0;
}
else if(r1==0x00){
return 1;
}
else if(r2==0x00){
return 2;
}
else if(r3==0x00){
return 3;
}
else return 4;
}
/*******************************************************************
* 函数: Toggle_Loop()
* 描述: 这里做的是检测被按下的行,本来是套了两个Row_Scan分别检测行列
* 输入值:无
* 返回值:无
*****************************************************************/
void Toggle_Loop(){
ledclose();
while(true){
switch(Row_Scan()){
case 0:led0(); break;
case 1:led2(); break;
case 2:led4(); break;
case 3:ledrun(1); break;
default:ledclose();break;
}Delay(24);
}
}
- 熟悉和掌握PWM模块的工作原理、模块结构和软件编程方法。
- 学会调整输出周期和占空比
板子上提供4个PWM发生器模块和一个控制模块,一共有8路PWM信号输出。每个PWM发生器输出2路PWM信号,分别是PWMA和PWMB,他们的可以选择是否共享时钟和频率,整个四个PWM模块之间的关系如下图所示:
实验程序流程:
/*******************************************************************
* 函数: PWM_Init()
* 描述: PWM初始化
* 输入值:无
* 返回值:无
*****************************************************************/
void PWM_Init()
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0);
PWMGenConfigure(PWM0_BASE, PWM_GEN_0|PWM_GEN_1,PWM_GEN_MODE_DOWN | PWM_GEN_MODE_NO_SYNC);
//配置系统时钟和配置重载值(如蜂鸣器,要注意范围2khz-4khz)
PWMGenPeriodSet(PWM0_BASE, PWM_GEN_0|PWM_GEN_1, 10000);
PWMPulseWidthSet(PWM0_BASE,PWM_OUT_1|PWM_OUT_2|PWM_OUT_3|PWM_OUT_4|PWM_OUT_5|PWM_OUT_6|PWM_OUT_7|PWM_OUT_0,50);
//PWM输出使能
PWMOutputState(PWM0_BASE, PWM_OUT_0_BIT |PWM_OUT_1_BIT |PWM_OUT_2_BIT | PWM_OUT_3_BIT, true);
//PWM把发生器使能
PWMGenEnable(PWM0_BASE, PWM_GEN_0);
PWMGenEnable(PWM0_BASE, PWM_GEN_1);
}
/*******************************************************************
* 函数: breathLED_run()
* 描述: 使呼吸灯闪烁,这里用循环让占空比从变大到变小,再利用PWMPulseWidthSet() 每次循环改变占空比形成亮灭。
* 输入值:无
* 返回值:无
*****************************************************************/
void breathLED_run(){
while(1)
{
for(ui32Loop=0;ui32Loop<1000;ui32Loop++)
{
;
}
PWMPulseWidthSet(PWM0_BASE, PWM_OUT_1,PWMPulseWidth);
PWMPulseWidthSet(PWM0_BASE, PWM_OUT_2,PWMPulseWidth);
PWMPulseWidthSet(PWM0_BASE, PWM_OUT_3,PWMPulseWidth);
PWMPulseWidth += flip;
if(PWMPulseWidth >= 9990)
{
flip = -5;
}
else if(PWMPulseWidth <= 50)
{
flip = 5;
}
}
}
- 了解单片机里中断的概念。
- 懂得声明中断向量,中断函数,改变中断优先级,最终学会使用中断。
"interrupt.h"
。
/*******************************************************************
* 函数: Handler_Init()
* 描述: 开启中断
* 输入值:无
* 返回值:无
*****************************************************************/
void Handler_Init()
{
SysCtlGPIOAHBEnable(SYSCTL_PERIPH_GPIOD);
//矩阵按键第四行
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
GPIOPinTypeGPIOInput(GPIO_PORTD_BASE,GPIO_PIN_0);
GPIOIntTypeSet(GPIO_PORTD_BASE,GPIO_PIN_0,GPIO_LOW_LEVEL);
GPIOIntEnable(GPIO_PORTD_BASE,GPIO_INT_PIN_0);
//定时器
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PERIODIC);
TimerIntEnable(TIMER0_BASE, TIMER_TIMB_TIMEOUT);
TimerEnable(TIMER0_BASE, TIMER_B);
TimerLoadSet(TIMER0_BASE, TIMER_B, sysClock_Fr/2000 );
//优先级设置,如下所示,优先级越高数字上越小
IntPrioritySet(INT_GPIOD,0x20);
IntPrioritySet(INT_TIMER0B,0x00);
IntEnable(INT_GPIOD); //开启相应中断向量
/*3.开启总中断*/
IntMasterEnable();
}
/*******************************************************************
* 函数: GPIOD_Handler()
* 描述: 矩阵按键第四行的中断函数
* 输入值:无
* 返回值:无
*****************************************************************/
void GPIOD_Handler()
{
uint32_t Status;
Status=GPIOIntStatus(GPIO_PORTD_BASE,true);
if(Status==GPIO_INT_PIN_0)
{
ledclose();
//ledon(0);
}
GPIOIntClear(GPIO_PORTD_BASE,Status);
}
/*******************************************************************
* 函数: GPIOD_Handler()
* 描述: 利用Timer实现一毫秒扫描一次键盘减轻cpu负担
* 输入值:无
* 返回值:无
*****************************************************************/
void Timer_Handler(){
unsigned long status;
status=TimerIntStatus(TIMER0_BASE,true);
if(status==TIMER_TIMB_TIMEOUT)
{
counter++;
if(counter==10)
{
counter=1;
switch(Row_Scan()){
case 0:{
LED_ON(1);Delay(24); break;
}
case 1:{
LED_ON(2);Delay(24); break;
}
case 2:{
LED_ON(3);Delay(24); break;
}
case 3:{
LED_ON(4);Delay(24); break;
}
default:ledclose(); break;
}
}
TimerIntClear(TIMER0_BASE, TIMER_TIMB_TIMEOUT);
}
}
- 了解总线通信原理
- 学会用C语言模拟时序
- 学会查找和利用板子上的资源,控制米字管
- 发送器:本次传送中发送数据(不包括地址和命令)到总线的器件。
- 接收器:本次传送中从总线接收数据(不包括地址和命令)的器件。
- 主机:初始化发送,产生时钟信号和终止发送的器件,它可以是发送器或接收器,主机通常是微控制器。
- 从机:被主机寻址的器件,他可以是发送器或接收器。
SDA | SCL | 总线状态 |
---|---|---|
高电平 | 高电平 | 空闲(stop之后) |
高到低 | 高电平 | START(之后视为忙状态) |
低到高 | 高电平 | STOP |
上表所示总线起止条件如图所示:
而每传送一个命令所包含的数据如下:一个起始位,从机地址,ACK校验位,命令字,ACK校验位,数据,最后再是一个ACK校验位,由此可以改变帧头帧尾制定通信协议。它们形式如下:
简单地说是一种总线,它的接收器和发射器都在总线上接收发送数据,也即分别通过SCL和SDA线接入总线。一定有主机和从机。板子上的资源和特性如下:
芯片 | 端口 | 管脚 |
---|---|---|
U4 | P1 | 2 |
P2 | 3 | |
P3 | 4 | |
P4 | 5 | |
P5 | 1 | |
U5 | P1 | 8 |
P2 | 9 | |
P3 | 10 | |
P4 | 11 | |
P5 | 12 | |
P6 | 13 | |
P7 | 14 | |
U6 | P1 | 16 |
P2 | 17 | |
P3 | 18 | |
P4 | 7 | |
P5 | 15 |
static const char tubeDigital[10][2]=
{ // SegmLow, SegHigh
{ 0x10, 0x3E }, // 0
{ 0x00, 0x18 }, // 1
{ 0x70, 0x2C }, // 2
{ 0x70, 0x26 }, // 3
{ 0x60, 0x32 }, // 4
{ 0x70, 0x16 }, // 5
{ 0x70, 0x1E }, // 6
{ 0x00, 0x26 }, // 7
{ 0x70, 0x3E }, // 8
{ 0x70, 0x36 }, // 9
};
/*******************************************************************
* 函数: I2C_Init()
* 描述: I2C初始化
* 输入值:无
* 返回值:无
*****************************************************************/
void I2C_Init()
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
/*B2设置为SCL时钟线,B3设置为SDA串行数据线*/
GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);
/*设置B的引脚复用功能为SCL和SDA*/
GPIOPinConfigure(GPIO_PB2_I2C0SCL);
GPIOPinConfigure(GPIO_PB3_I2C0SDA);
GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0); //使能I2C0模块
/* 设I2C主机模式, 使用系统时钟, 400kbps的快速模式(false普通模式100Kbps)*/
I2CMasterInitExpClk(I2C0_BASE,1000000, true);
I2CMasterEnable(I2C0_BASE); //使能I2C0主机模式
I2CSlaveEnable(I2C0_BASE);//使能I2C从机模式
}
/********************************************************************
* 函数: PCA9557_Init()
* 描述: PCA9557初始化
* 输入值:无
* 返回值:无
******************************************************************/
void PCA9557_Init()
{ uint8_t SendBuff[2] = {PCA9557_REG_CONFIG, 0x00};
//PCA9557_REG_CONFIG(COMMAND BYTE)配置成读写模式
I2C_SendBuff(I2C0_ADDR_TUBE_SEL, SendBuff, 2);
//U21管选 I2C0_ADDR_TUBE_SEL (SLAVE ADDR)
I2C_SendBuff(I2C0_ADDR_TUBE_SEG_LOW, SendBuff, 2);
//U22管选 I2C0_ADDR_TUBE_SEG_LOW(SLAVE ADDR)
I2C_SendBuff(I2C0_ADDR_TUBE_SEG_HIGH, SendBuff, 2);
//U23管选 I2C0_ADDR_TUBE_SEG_HIGH(SLAVE ADDR)
}
/*******************************************************************
* 函数: MZG_run()
* 描述: 点亮米字管为a,b,c,d(在while里的动态显示)
* 输入值:uint8_t a,b,c,d
* 返回值:无
*****************************************************************/
void MGZ_run(){
int t=50;//这个延时时间
I2C_ClearTheTube(); //清屏
I2C_U4TubeSelect(~0x20); //选择数字管1
I2C_U5TubeLowPinControl(tubeDigital[a][0]);//拉低U5的引脚
I2C_U3TubeHighPinControl(tubeDigital[a][1]);//拉高U3引脚
DelayMs(t);
I2C_ClearTheTube(); //清屏
I2C_U4TubeSelect(~0x02); //选择数字管2
I2C_U5TubeLowPinControl(tubeDigital[b][0]);//拉低U5的引脚
I2C_U3TubeHighPinControl(tubeDigital[b][1]);//拉高U3引脚
DelayMs(t);
I2C_ClearTheTube(); //清屏
I2C_U4TubeSelect(~0x04); //选择数字管3
I2C_U5TubeLowPinControl(tubeDigital[c][0]);//拉低U5的引脚
I2C_U3TubeHighPinControl(tubeDigital[c][1]);//拉高U3引脚
DelayMs(t);
I2C_ClearTheTube(); //清屏
I2C_U4TubeSelect(~0x08); //选择数字管4
I2C_U5TubeLowPinControl(tubeDigital[d][0]);//拉低U5的引脚
I2C_U3TubeHighPinControl(tubeDigital[d][1]);//拉高U3引脚
DelayMs(t);
}
- 学习ADC模块原理和串口通信的原理
- 学习使用ADC模块转化外设传感器数据变为可调用的数字信息
- 将信息用UART输出
序列发生器 | 采样数 | FIFO深度 |
---|---|---|
SS3 | 1 | 1 |
SS2 | 2 | 4 |
SS1 | 3 | 4 |
SS0 | 8 | 8 |
SS处理采样控制和数据采集,所有序列发生器的实现方式相同,但采样数和FIFO深度不同。每个FIFO单元均为一个32位的字,低12位包含的是转换结果。
//配置PE3口为ADC单端采样模式,使用采样序列3采样内置温度感应器,处理器信号触发方式。
void main(){
int pui32ADC0Value;
//初始化系统时钟
g_ui32SysClock=SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ|SYSCTL_OSC_MAIN|SYSCTL_USE_PLL|SYSCTL_CFG_VCO_480),120000000);
//开启ADC0时钟
SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
//使能温度传感器PE3
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
//将PE3口配置成AD输入模式
GPIOPinTypeADC(GPIO_PORTE_BASE,GPIO_PIN_3);
//使用采样序列3来采样,ADC_TRIGGER_PROCESSOR为设定触发方式为控制器触发,由ADCProcessorTrigger()配合使用。
ADCSequenceConfigure(ADC0_BASE,3,ADC_TRIGGER_PROCESSOR,0);
//配置采样序列3的步骤0,配置模拟通道0(ADC_CTL_CH0)、采样结束产生中断(ADC_CTL_IE),转化结束后告诉ADC逻辑转化结束
ADCSequenceStepConfigure(ADC0_BSE,3,0,ADC_CTL_CH0|ADC_CTL_IE|ADC_CTL_END);
//使能采样序列3
ADCSequenceEnable(ADC0_BASE,3);
//开始采样前先清除采样序列3产生的中断
ADCIntClear(ADC0_BASE,3);
while(1){
//触发ADC0SS3。
ADCProcessorTrigger(ADC0_BASE,3);
//等待转换结束
while(!ADCIntStatus(ADC0_BASE,3,false)){}
//清除中断标志
ADCIntClear(ADC0_BASE,3);
//读取ADC0采样序列SS3的转化值,将结果存在pui32ADC0Value
ADCSequenceDataGet(ADC0_BASE,3,pui32ADC0Value);
//延时
SysCtlDelay(g_ui32Sysclock/12);
}
}
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#include "inc/hw_gpio.h"
#include "driverlib/adc.h"
UART(Universal Asynchronous Receiver/Transmitter), 异步串行通信接口,它可以实现数据的并串行转换,相对于同步模式,异步模式不需要一个专门的时钟信号来控制数据的收发,因此发送数据时位与位之间的间隙可以任意改变,但是并不是说不需要时钟信号,而是通过系统时钟或全局备用时钟产生一个可编程的波特时钟来控制发送数据。
- 接收处理器内部的并行数据,通过串行发送总线UnTX以异步通信的方式发送出去
- 输入接收总线UnRX上的串行数据,转换为并行数据后返回给处理器处理
- 数据接收或处理完后,经过T/R缓冲区FIFO,
标准的异步通信包括起始位,停止位,奇偶校验位。控制逻辑输出串行位流时,最先输出起始位,然后输出若干数据位(最低有效位在前),奇偶校验位和停止位。
接收逻辑单元在检测到有效的起始脉冲后,对接收到的串行位码流进行串-并转换,在接收过程中还要进行溢出错误检测、奇偶校验、帧错误检测、线终止检测、并将这些状态随数据一同写入接收FIFO中。
波特率分频系数是由16位整数部分和6位小数部分组成的22位二进制数,由此决定位时间,其中整数由UART波特率分频值整数(UARTIBRD)寄存器加载,小数通过UART波特率分频值小数(UARTFBRD)寄存器加载。波特率分频值(BRD)和系统时钟之间关系如下:
BRD=BRDI+BRDF=UARTSysClk/(ClkDiv*波特率)
式中UARTSysClk是连接到UART的系统时钟,ClkDiv是一个常数,取值为16或8(对应UARTCTL寄存器里第五位HSE=0/1,因此UART模块产生的内部波特率参考时钟频率总为波特率的8或16倍,分别称为)。默认情况下该系统时钟为‘时钟控制’中描述的主系统时钟,6位小数部分(寄存器[UARTFBRD]里[DIVFRAC]位域的值)计算方法如下:
UARTFBRD[DIVFRAC]=integer(BRDF*64+0.5)
即将波特率除数的小数部分乘64,加0.5以抵消舍入误差。需注意的是,梗概波特率除数之后,必须写一次(高字节)UARTLCRH寄存器,更改内容才会生效。
uart有8个模块,其中uart0是我们要用到的,它有调制解调器的功能(调制解调器流控制和调制解调器状态)//UART0使用PA0,PA1两个引脚,因此要使能GPIOA模块。
//UART0使用PA0,PA1两个引脚,首先使能GPIOA模块
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
//GPIO管脚复用,所以要对PA0,PA1两个引脚功能进行选择,这里将他们选择为执行UART0模块功能
GPIOPinConfigure(GPIO_PA0_U0RX);//PA0用于接收数据
GPIOPinConfigure(GPIO_PA1_U0TX);//PA1用于发送数据
//将PA0,PA1作为UART功能使用前进行配置
GPIOPinTypeUART(GPIO_PORTA_BASE,GPIO_PIN_0|GPIO_PIN_1);
UARTStdioConfig(0,115200,g_ui32SysClock);
//sysctl.h
//使能外设模块基址
void SysCtlPeripheralEnable(uint32_t ui32Peripheral);
//函数的定义和ui8Pins在gpio.h
//ui32PinConfig在pin_map.h,ui32Port在hw_mammap.h
//GPIOPinConfigure()一般和GPIOPinType...()一起使用来配置引脚。
void GPIOPinConfigure(uint32_t ui32PinConfig);
void GPIOPinTypeUART(uint32_t ui32Port, uint8_t ui8Pins);
/*******************************************************************
* 函数: ADC_Init()
* 描述: 初始化ADC0序列3和滚轮
* 输入值:无
* 返回值:无
*****************************************************************/
void ADC_Init()
{
// 初始化ADC0/PD7 AIN4 共20通道最大AIN19 分辨率为12bit 最大值4096
SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); //可选两个模块 ADC0和ADC1
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_7);
ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_PROCESSOR, 0);
ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH4 | ADC_CTL_END | ADC_CTL_IE);
ADCSequenceEnable(ADC0_BASE, 3);
ADC0_HandlerFlag = false; //中断未发生
}
/*******************************************************************
* 函数: ADC_work()
* 描述: 数据采集,转化并用串口输出
* 输入值:无
* 返回值:无
*****************************************************************/
void ADC_work()
{
uint32_t ADC0_SS3v;
uint32_t ADC0_result;
ADCProcessorTrigger(ADC0_BASE, 3);
while(!ADCIntStatus(ADC0_BASE, 3, false)) ;
ADCSequenceDataGet(ADC0_BASE, 3, &ADC0_SS3v);
ADC0_result=(ADC0_SS3v * 3.3 *1000)/4096;
UARTprintf("V:%04d \n ", ADC0_result);
}
- 依旧是通信,这次是用控制板子上的三轴加速度传感器ADXL345。
- 这次不用串口,而是通过得到的数据识别板子的姿态。因为ADXL345本身就会把得到的数据以数字形式存放在寄存器里,所以直接读取即可,不需要用到模数转换ADC模块。
- 学会单步观察参数调节程序。
- 需要用到模块:ADXL345,。
引脚编号 | 引脚名称 | 描述 |
---|---|---|
1 | Vdd | 数字接口电源电压 |
2 | GND | 该引脚必须接地 |
3 | RESERVED | 保留。该引脚必须连接到VC或者保持断开 |
4 | GND | 该引脚必须接地 |
5 | GND | 该引脚必须接地 |
6 | VC | 电源电压 |
7 | CS | 片选 |
8 | INT1 | 中断1输出 |
9 | INT2 | 中断2输出 |
10 | NC | 内部不连接 |
11 | RESERVED | 保留。该引脚必须接地或保持断开 |
12 | SDO/ALT ADDRESS | 串行数据输出(SPI4线)备用I2C地址选择 |
13 | SDA/SDI/SDIO | 串行数据(I2C)串行数据输入(SPI4)/串行数据输入和输出(SPI3) |
14 | SCL/SCLK | 串行通信时钟,SCL为I2C时钟SCLK为SPI时钟 |
I2C状态下的引脚配置
芯片的寄存器信息
/*******************************************************************
* 函数: ADXL345_run()
* 描述: 读取处理加速度器寄存器数据,识别板子十种不同姿态
* 输入值:无
* 返回值:无
*****************************************************************/
void ADXL345_run(){
ADXL345_Read(DataXYZ); //连续6次分别读取0x32-0x37中的数据。
ADXL345_DataProcess(DataXYZ,DataMg); //对数据进行处理
if((DataMg[0] == OneG)&&(DataMg[3]== Positive))
{ ledclose(); LED_ON(4); }
else if((DataMg[0] == OneG)&&(DataMg[3]== Negative))
{ ledclose();LED_ON(0); }
else if((DataMg[1] == OneG)&&(DataMg[4]== Negative))
{ ledclose(); LED_ON(6); }
else if((DataMg[1] == OneG)&&(DataMg[4]== Positive))
{ ledclose(); LED_ON(2); }
else if((DataMg[2] == OneG)&&(DataMg[5]== Negative))
{ ledclose(); }
//*************************************************************8
else if((DataMg[3]== Negative)&&(DataMg[4]== Negative))
{ ledclose(); LED_ON(7); }
else if((DataMg[3]== Negative)&&(DataMg[4]== Positive))
{ ledclose(); LED_ON(1); }
else if((DataMg[3]== Positive)&&(DataMg[4]== Positive))
{ ledclose(); LED_ON(3); }
else if((DataMg[3]== Positive)&&(DataMg[4]== Negative))
{ ledclose(); LED_ON(5); }
}