搜索
bottom↓
回复: 135

九九的STM32学习笔记,小弟才入门,高手表骂~~【恢复】

[复制链接]

出0入0汤圆

发表于 2008-12-15 19:51:09 | 显示全部楼层 |阅读模式
上周4终于买了块万利的STM32开发板,武汉本地的万利代理处买的,之前问了好久都没货,这次终于有了:)199还开了发票,尽管老板是分不愿意,没利润阿,再开个票亏了。。。

调了几个程序,觉得蛮爽,就在edn上注册了个博客,把相关代码放了上面,方便大家阅读

那里的代码我做了颜色高亮,看起来很舒服:)

这是地址:http://blog.ednchina.com/jjldc/

咱也就初学者水平,目前对STM32还处在学习各种模块的阶段,so,高手们请多多指点,别介意小弟啰嗦把这点P东西都放网上~~

学这高级单片机,是想过几天把它用到雕刻机的控制上,解释下G代码呀,插补个圆弧直线啥的,顺便还和PLC通讯通讯:)



STM32笔记(零)我的STM32工程模板



  这是我自己的STM32工程模板,其实和网上所有的都一样,其中包括IAR和MDK两个文件,各自包含FWLib2.0,解压缩后修改文件名即可使用。

  用法同网上的其他文件一致,用户代码在user文件夹下,main.c和stm32f10x_it.c

  传一份上来供大家使用:)

点击此处下载 ourdev_545097.rar(文件大小:337K) (原文件名:STM32_code.rar) 



本贴被 jjldc 编辑过,最后修改时间:2008-12-15,19:56:39.

出0入0汤圆

 楼主| 发表于 2008-12-15 19:53:11 | 显示全部楼层
STM32笔记(一)TIM模块定时器向上溢出 & 输出比较

原文地址:http://blog.ednchina.com/jjldc/187975/message.aspx

首先我们必须肯定ST公司的实力,也承认STM32的确是一款非常不错的Cortex-M3核单片机,但是,他的手册实在是让人觉得无法理解,尤其是其中的TIM模块,没有条理可言,看了两天几乎还是不知所云,让人很是郁闷。同时配套的固件库的说明也很难和手册上的寄存器对应起来,研究起来非常费劲!功能强大倒是真的,但至少也应该配套一个让人看的明白的说明吧~~

  两天时间研究了STM32定时器的最最基础的部分,把定时器最基础的两个功能实现了,余下的功能有待继续学习。

  首先有一点需要注意:FWLib固件库目前的最新版应该是V2.0.x,V1.0.x版本固件库中,TIM1模块被独立出来,调用的函数与其他定时器不同;在V2.0系列版本中,取消了TIM1.h,所有的TIM模块统一调用TIM.h即可。网络上流传的各种代码有许多是基于v1版本的固件库,在移植到v2版本固件库时,需要做些修改。本文的所有程序都是基于V2.0固件库。



  以下是定时器向上溢出示例代码:



C语言: TIM1模块产生向上溢出事件

//Step1.时钟设置:启动TIM1

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);



//Step2.中断NVIC设置:允许中断,设置优先级

NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQChannel;    //更新事件

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;   //抢占优先级0

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;          //响应优先级1

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //允许中断

NVIC_Init(&NVIC_InitStructure);                             //写入设置



//Step3.TIM1模块设置

void TIM_Configuration(void)

{

TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;

TIM_OCInitTypeDef TIM_OCInitStructure;





//TIM1 使用内部时钟

//TIM_InternalClockConfig(TIM1);



//TIM1基本设置

//设置预分频器分频系数71,即APB2=72M, TIM1_CLK=72/72=1MHz

//TIM_Period(TIM1_ARR)=1000,计数器向上计数到1000后产生更新事件,计数值归零

//向上计数模式

//TIM_RepetitionCounter(TIM1_RCR)=0,每次向上溢出都产生更新事件

TIM_BaseInitStructure.TIM_Period = 1000;

TIM_BaseInitStructure.TIM_Prescaler = 71;

TIM_BaseInitStructure.TIM_ClockDivision = 0;

TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_BaseInitStructure.TIM_RepetitionCounter = 0;

TIM_TimeBaseInit(TIM1, &TIM_BaseInitStructure);



//清中断,以免一启用中断后立即产生中断

TIM_ClearFlag(TIM1, TIM_FLAG_Update);

//使能TIM1中断源

TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);



//TIM1总开关:开启

TIM_Cmd(TIM1, ENABLE);

}



//Step4.中断服务子程序:

void TIM1_UP_IRQHandler(void)

{

GPIOC->ODR ^= (1<<4);                         //闪灯

TIM_ClearITPendingBit(TIM1, TIM_FLAG_Update); //清中断

}



  下面是输出比较功能实现TIM1_CH1管脚输出指定频率的脉冲:



C语言: TIM1模块实现输出比较,自动翻转并触发中断

//Step1.启动TIM1,同时还要注意给相应功能管脚启动时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);



//Step2. PA.8口设置为TIM1的OC1输出口

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);



//Step3.使能TIM1的输出比较匹配中断

NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQChannel;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);



//Step4. TIM模块设置

void TIM_Configuration(void)

{

    TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;

    TIM_OCInitTypeDef TIM_OCInitStructure;





    //TIM1基本计数器设置

    TIM_BaseInitStructure.TIM_Period = 0xffff;                      //这里必须是65535 

    TIM_BaseInitStructure.TIM_Prescaler = 71;                       //预分频71,即72分频,得1M

    TIM_BaseInitStructure.TIM_ClockDivision = 0;

    TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;

    TIM_BaseInitStructure.TIM_RepetitionCounter = 0;

    TIM_TimeBaseInit(TIM1, &TIM_BaseInitStructure);



    //TIM1_OC1模块设置

    TIM_OCStructInit(& TIM_OCInitStructure); 

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;             //管脚输出模式:翻转

    TIM_OCInitStructure.TIM_Pulse = 2000;                           //翻转周期:2000个脉冲

    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   //使能TIM1_CH1通道

    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;       //输出为正逻辑

    TIM_OC1Init(TIM1, &TIM_OCInitStructure);                        //写入配置



    //清中断

    TIM_ClearFlag(TIM1, TIM_FLAG_CC1);



    //TIM1中断源设置,开启相应通道的捕捉比较中断

    TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);



    //TIM1开启

    TIM_Cmd(TIM1, ENABLE);

    //通道输出使能

    TIM_CtrlPWMOutputs(TIM1, ENABLE);

}



Step5.中断服务子程序

void TIM1_CC_IRQHandler(void)

{

    u16 capture;

    if(TIM_GetITStatus(TIM1, TIM_IT_CC1) == SET)

    {

        TIM_ClearITPendingBit(TIM1, TIM_IT_CC1 );

        capture = TIM_GetCapture1(TIM1);

        TIM_SetCompare1(TIM1, capture + 2000);

        //这里解释下:

        //将TIM1_CCR1的值增加2000,使得下一个TIM事件也需要2000个脉冲,

        //另一种方式是清零脉冲计数器

        //TIM_SetCounter(TIM2,0x0000);

    }

}



  关于TIM的操作,要注意的是STM32处理器因为低功耗的需要,各模块需要分别独立开启时钟,所以,一定不要忘记给用到的模块和管脚使能时钟,因为这个原因,浪费了我好多时间阿~~!

下一回,将介绍TIM模块PWM的功能!

出0入0汤圆

 楼主| 发表于 2008-12-15 19:53:28 | 显示全部楼层
STM32笔记(二)TIM模块产生PWM

原文地址:http://blog.ednchina.com/jjldc/188086/message.aspx

     这个是STM32的PWM输出模式,STM32的TIM1模块是增强型的定时器模块,天生就是为电机控制而生,可以产生3组6路PWM,同时每组2路PWM为互补,并可以带有死区,可以用来驱动H桥。

  下面的代码,是利用TIM1模块的1、2通道产生一共4路PWM的代码例子,类似代码也可以参考ST的固件库中相应example

C语言: TIM1模块产生PWM,带死区

    

//Step1.开启TIM和相应端口时钟

//启动GPIO

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | \

                       RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,\

                       ENABLE);

//启动AFIO

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

//启动TIM1

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);



//Step2. GPIO做相应设置,为AF输出

//PA.8/9口设置为TIM1的OC1输出口

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);



//PB.13/14口设置为TIM1_CH1N和TIM1_CH2N输出口

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOB, &GPIO_InitStructure);



//Step3. TIM模块初始化

void TIM_Configuration(void)

{

    TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;

    TIM_OCInitTypeDef TIM_OCInitStructure;

    TIM_BDTRInitTypeDef TIM_BDTRInitStructure;



    //TIM1基本计数器设置(设置PWM频率)

    //频率=TIM1_CLK/(ARR+1)

    TIM_BaseInitStructure.TIM_Period = 1000-1;

    TIM_BaseInitStructure.TIM_Prescaler = 72-1;

    TIM_BaseInitStructure.TIM_ClockDivision = 0;

    TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;

    TIM_BaseInitStructure.TIM_RepetitionCounter = 0;

    TIM_TimeBaseInit(TIM1, &TIM_BaseInitStructure);

    //启用ARR的影子寄存器(直到产生更新事件才更改设置)

    TIM_ARRPreloadConfig(TIM1, ENABLE);





    //TIM1_OC1模块设置(设置1通道占空比)

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;

    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;

    TIM_OCInitStructure.TIM_Pulse = 120;

    TIM_OC1Init(TIM1, &TIM_OCInitStructure);

    //启用CCR1寄存器的影子寄存器(直到产生更新事件才更改设置)

    TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);



    //TIM2_OC2模块设置(设置2通道占空比)

    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;

    TIM_OCInitStructure.TIM_Pulse = 680;

    TIM_OC2Init(TIM1, &TIM_OCInitStructure);

    //启用CCR2寄存器的影子寄存器(直到产生更新事件才更改设置)

    TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);

   

    //死区设置

    TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;

    TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;

    TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF;

    TIM_BDTRInitStructure.TIM_DeadTime = 0x90;  //这里调整死区大小0-0xff

    TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;

    TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;

    TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;

    TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);

   

    //TIM1开启

    TIM_Cmd(TIM1, ENABLE);

    //TIM1_OC通道输出PWM(一定要加)

    TIM_CtrlPWMOutputs(TIM1, ENABLE);



}

  

  其实,PWM模块还可以有很多花样可以玩,比方在异常时(如CPU时钟有问题),可以紧急关闭输出,以免发生电路烧毁等严重事故。

出0入0汤圆

 楼主| 发表于 2008-12-15 19:53:49 | 显示全部楼层
STM32笔记(三)ADC、DMA、USART的综合练习

原文地址:http://blog.ednchina.com/jjldc/188553/message.aspx

这是一个综合的例子,演示了ADC模块、DMA模块和USART模块的基本使用。

  我们在这里设置ADC为连续转换模式,常规转换序列中有两路转换通道,分别是ADC_CH10(PC0)和ADC_CH16(片内温度传感器)。因为使用了自动多通道转换,数据的取出工作最适合使用DMA方式取出,so,我们在内存里开辟了一个u16 AD_Value[2]数组,并设置了相应的DMA模块,使ADC在每个通道转换结束后启动DMA传输,其缓冲区数据量为2个HalfWord,使两路通道的转换结果自动的分别落到AD_Value[0]和AD_Value[1]中。

  然后,在主函数里,就无需手动启动AD转换,等待转换结束,再取结果了。我们可以在主函数里随时取AD_Value中的数值,那里永远都是最新的AD转换结果。

  如果我们定义一个更大的AD_Value数组,并调整DMA的传输数据量(BufferSize)可以实现AD结果的循环队列存储,从而可以进行各种数字滤波算法。

  接着,取到转换结果后,根据V=(AD_Value/4096)*Vref+的公式可以算出相应通道的电压值,也可以根据  T(℃) =  (1.43 - Vad)/34*10^(-6) + 25的算法,得到片内温度传感器的测量温度值了。

  通过重新定义putchar函数,及包含"stdio.h"头文件,我们可以方便的使用标准C的库函数printf(),实现串口通信。

  相关的官方例程,可以参考FWLib V2.0的ADC\ADC1_DMA和USART\printf两个目录下的代码。



本代码例子是基于万利199的开发板EK-STM32F实现,CPU=STM32F103VBT6





/******************************************************************************

* 本文件实现ADC模块的基本功能

* 设置ADC1的常规转换序列包含CH10和CH16(片内温度传感器)

* 设置了连续转换模式,并使用DMA传输

* AD转换值被放在了AD_Value[2]数组内,[0]保存CH0结果,[1]保存CH16结果

* GetVolt函数计算[0]的值对应的电压值(放大100倍,保留2位小数)

* GetTemp函数计算[1]的值对应的温度值,计算公式在相应函数内有说明

*  作者:jjldc(九九)

*******************************************************************************/



/* Includes ------------------------------------------------------------------*/

#include "stm32f10x_lib.h"

#include "stdio.h"



/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

#define ADC1_DR_Address    ((u32)0x4001244C)

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/

vu16 AD_Value[2];

vu16 i=0;

s16  Temp;

u16  Volt;



/* Private function prototypes -----------------------------------------------*/

void RCC_Configuration(void);

void GPIO_Configuration(void);

void NVIC_Configuration(void);

void USART1_Configuration(void);

void ADC1_Configuration(void);

void DMA_Configuration(void);



int fputc(int ch, FILE *f);

void Delay(void);

u16 GetTemp(u16 advalue);

u16 GetVolt(u16 advalue);

/* Private functions ---------------------------------------------------------*/

/*******************************************************************************

* Function Name  : main

* Description    : Main program.

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

int main(void)

{

    RCC_Configuration();

    GPIO_Configuration();

    NVIC_Configuration();

    USART1_Configuration();

    DMA_Configuration();

    ADC1_Configuration();

   

    //启动第一次AD转换

    ADC_SoftwareStartConvCmd(ADC1, ENABLE);

    //因为已经配置好了DMA,接下来AD自动连续转换,结果自动保存在AD_Value处  

   

    while (1)

    {

        Delay();

        Temp = GetTemp(AD_Value[1]);

        Volt = GetVolt(AD_Value[0]);

        USART_SendData(USART1, 0x0c);       //清屏

        //注意,USART_SendData函数不检查是否发送完成

        //等待发送完成

        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);



        printf("电压:%d.%d\t温度:%d.%d℃\r\n", \

            Volt/100, Volt%100, Temp/100, Temp%100);

       

    }

}



/*******************************************************************************

* Function Name  : 重定义系统putchar函数int fputc(int ch, FILE *f)

* Description    : 串口发一个字节

* Input          : int ch, FILE *f

* Output         :

* Return         : int ch

*******************************************************************************/

int fputc(int ch, FILE *f)

{

    //USART_SendData(USART1, (u8) ch);

    USART1->DR = (u8) ch;

   

    /* Loop until the end of transmission */

    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)

    {

    }



    return ch;

}



/*******************************************************************************

* Function Name  : Delay

* Description    : 延时函数

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void Delay(void)

{

    u32 i;

    for(i=0;i<0x4f0000;i++);

    return;

}                           



/*******************************************************************************

* Function Name  : GetTemp

* Description    : 根据ADC结果计算温度

* Input          : u16 advalue

* Output         :

* Return         : u16 temp

*******************************************************************************/

u16 GetTemp(u16 advalue)

{

    u32 Vtemp_sensor;

    s32 Current_Temp;

   

//    ADC转换结束以后,读取ADC_DR寄存器中的结果,转换温度值计算公式如下:

//          V25 - VSENSE

//  T(℃) = ------------  + 25

//           Avg_Slope

//   V25:  温度传感器在25℃时 的输出电压,典型值1.43 V。

//  VSENSE:温度传感器的当前输出电压,与ADC_DR 寄存器中的结果ADC_ConvertedValue之间的转换关系为:

//            ADC_ConvertedValue * Vdd

//  VSENSE = --------------------------

//            Vdd_convert_value(0xFFF)

//  Avg_Slope:温度传感器输出电压和温度的关联参数,典型值4.3 mV/℃。



    Vtemp_sensor = advalue * 330 / 4096;

    Current_Temp = (s32)(143 - Vtemp_sensor)*1000/34 + 2500;

    return (s16)Current_Temp;

} 





/*******************************************************************************

* Function Name  : GetVolt

* Description    : 根据ADC结果计算电压

* Input          : u16 advalue

* Output         :

* Return         : u16 temp

*******************************************************************************/

u16 GetVolt(u16 advalue)

{

    return (u16)(advalue * 330 / 4096);

}

                         



/*******************************************************************************

* Function Name  : RCC_Configuration

* Description    : 系统时钟设置

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void RCC_Configuration(void)

{

    ErrorStatus HSEStartUpStatus;



    //使能外部晶振

    RCC_HSEConfig(RCC_HSE_ON);

    //等待外部晶振稳定

    HSEStartUpStatus = RCC_WaitForHSEStartUp();

    //如果外部晶振启动成功,则进行下一步操作

    if(HSEStartUpStatus==SUCCESS)

    {

        //设置HCLK(AHB时钟)=SYSCLK

        RCC_HCLKConfig(RCC_SYSCLK_Div1);



        //PCLK1(APB1) = HCLK/2

        RCC_PCLK1Config(RCC_HCLK_Div2);



        //PCLK2(APB2) = HCLK

        RCC_PCLK2Config(RCC_HCLK_Div1);

       

        //设置ADC时钟频率

        RCC_ADCCLKConfig(RCC_PCLK2_Div2);



        //FLASH时序控制

        //推荐值:SYSCLK = 0~24MHz   Latency=0

        //        SYSCLK = 24~48MHz  Latency=1

        //        SYSCLK = 48~72MHz  Latency=2

        FLASH_SetLatency(FLASH_Latency_2);

        //开启FLASH预取指功能

        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);



        //PLL设置 SYSCLK/1 * 9 = 8*1*9 = 72MHz

        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

        //启动PLL

        RCC_PLLCmd(ENABLE);

        //等待PLL稳定

        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

        //系统时钟SYSCLK来自PLL输出

        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

        //切换时钟后等待系统时钟稳定

        while(RCC_GetSYSCLKSource()!=0x08);



       

    }



    //下面是给各模块开启时钟

    //启动GPIO

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | \

                           RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,\

                           ENABLE);

    //启动AFIO

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

    //启动USART1

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

    //启动DMA时钟

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    //启动ADC1时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);



}





/*******************************************************************************

* Function Name  : GPIO_Configuration

* Description    : GPIO设置

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void GPIO_Configuration(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;



    //PC口4567脚设置GPIO输出,推挽 2M

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;

    GPIO_Init(GPIOC, &GPIO_InitStructure);



    //KEY2 KEY3 JOYKEY

    //位于PD口的3 4 11-15脚,使能设置为输入

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_11 | GPIO_Pin_12 |\

        GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_Init(GPIOD, &GPIO_InitStructure);



    //USART1_TX

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

   

    //USART1_RX

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

   

    //ADC_CH10--> PC0

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

    GPIO_Init(GPIOC, &GPIO_InitStructure);



}







/*******************************************************************************

* Function Name  : NVIC_Configuration

* Description    : NVIC设置

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void NVIC_Configuration(void)

{

    NVIC_InitTypeDef NVIC_InitStructure;



#ifdef  VECT_TAB_RAM

    // Set the Vector Table base location at 0x20000000

    NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);

#else  /* VECT_TAB_FLASH  */

    // Set the Vector Table base location at 0x08000000

    NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);

#endif



    //设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    //串口中断打开

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

}





/*******************************************************************************

* Function Name  : USART1_Configuration

* Description    : NUSART1设置

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void USART1_Configuration(void)

{

    USART_InitTypeDef USART_InitStructure;

   

    USART_InitStructure.USART_BaudRate = 19200;

    USART_InitStructure.USART_WordLength = USART_WordLength_8b;

    USART_InitStructure.USART_StopBits = USART_StopBits_1;

    USART_InitStructure.USART_Parity = USART_Parity_No;

    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;

    USART_Init(USART1, &USART_InitStructure);

   

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

   

    USART_Cmd(USART1, ENABLE);

}



/*******************************************************************************

* Function Name  : ADC1_Configuration

* Description    : ADC1设置(包括ADC模块配置和自校准)

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void ADC1_Configuration(void)

{

    ADC_InitTypeDef ADC_InitStructure;



    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

    ADC_InitStructure.ADC_ScanConvMode = ENABLE;

    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;  //连续转换开启

    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

    ADC_InitStructure.ADC_NbrOfChannel = 2;     //设置转换序列长度为2

    ADC_Init(ADC1, &ADC_InitStructure);

   

    //ADC内置温度传感器使能(要使用片内温度传感器,切忌要开启它)

    ADC_TempSensorVrefintCmd(ENABLE);

   

    //常规转换序列1:通道10

    ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_13Cycles5);

    //常规转换序列2:通道16(内部温度传感器),采样时间>2.2us,(239cycles)

    ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 2, ADC_SampleTime_239Cycles5);

   

    // Enable ADC1

    ADC_Cmd(ADC1, ENABLE);

    // 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)

    ADC_DMACmd(ADC1, ENABLE);

   

    // 下面是ADC自动校准,开机后需执行一次,保证精度

    // Enable ADC1 reset calibaration register

    ADC_ResetCalibration(ADC1);

    // Check the end of ADC1 reset calibration register

    while(ADC_GetResetCalibrationStatus(ADC1));



    // Start ADC1 calibaration

    ADC_StartCalibration(ADC1);

    // Check the end of ADC1 calibration

    while(ADC_GetCalibrationStatus(ADC1));

    // ADC自动校准结束---------------

   

}



/*******************************************************************************

* Function Name  : DMA_Configuration

* Description    : DMA设置:从ADC模块自动读转换结果至内存

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void DMA_Configuration(void)

{

    DMA_InitTypeDef DMA_InitStructure;

   

    DMA_DeInit(DMA1_Channel1);

    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;

    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Value;

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

    //BufferSize=2,因为ADC转换序列有2个通道

    //如此设置,使序列1结果放在AD_Value[0],序列2结果放在AD_Value[1]

    DMA_InitStructure.DMA_BufferSize = 2;

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

    //循环模式开启,Buffer写满后,自动回到初始地址开始传输

    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

    DMA_InitStructure.DMA_Priority = DMA_Priority_High;

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(DMA1_Channel1, &DMA_InitStructure);

    //配置完成后,启动DMA通道

    DMA_Cmd(DMA1_Channel1, ENABLE);

}

最后附上MDK的工程文件,可以直接运行:

点击此处下载 ourdev_545137.rar(文件大小:173K) (原文件名:AD_2_Channel_temp_DMA.rar) 



本贴被 jjldc 编辑过,最后修改时间:2008-12-15,19:55:42.

出0入0汤圆

 楼主| 发表于 2008-12-15 19:55:11 | 显示全部楼层
STM32笔记(四)DMA、USART的演示

原文地址:http://blog.ednchina.com/jjldc/188556/message.aspx

 这里有个小小的例子,来演示DMA模块与系统程序并行工作。

  用串口以低波特率发送一个10K的数据,花费近10s时间,此时按照以往方法,CPU要不断等待数据发送、送数据;或者送数据、进中断、送数据,处理起来比较消耗时间。

  使用了DMA功能以后,用户程序中只需配置好DMA,开启传输后,再也不需要操心,10K数据完成后会有标志位或中断产生,期间可以做任何想做的事,非常方便。

  这个是相应的代码例子,基于STM32F103VBT6





/******************************************************************************

* 本文件实现串口发送功能(通过重构putchar函数,调用printf;或者USART_SendData()

* 这里是一个用串口实现大量数据传输的例子,使用了DMA模块进行内存到USART的传输

* 每当USART的发送缓冲区空时,USART模块产生一个DMA事件,

* 此时DMA模块响应该事件,自动从预先定义好的发送缓冲区中拿出下一个字节送给USART

* 整个过程无需用户程序干预,用户只需启动DMA传输传输即可

* 在仿真器调试时,可以在数据传输过程中暂停运行,此时DMA模块并没有停止

* 串口依然发送,表明DMA传输是一个独立的过程。

* 同时开启接收中断,在串口中断中将数据存入缓冲区,在main主循环中处理

* 作者:jjldc(九九)

* 代码硬件基于万利199元的EK-STM32F开发板,CPU=STM32F103VBT6

*******************************************************************************/



/* Includes ------------------------------------------------------------------*/

#include "stm32f10x_lib.h"

#include "stdio.h"



/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

#define USART1_DR_Base  0x40013804



/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/

#define SENDBUFF_SIZE   10240

vu8 SendBuff[SENDBUFF_SIZE];

vu8 RecvBuff[10];

vu8 recv_ptr;



/* Private function prototypes -----------------------------------------------*/

void RCC_Configuration(void);

void GPIO_Configuration(void);

void NVIC_Configuration(void);

void DMA_Configuration(void);

void USART1_Configuration(void);



int fputc(int ch, FILE *f);

void Delay(void);



/* Private functions ---------------------------------------------------------*/

/*******************************************************************************

* Function Name  : main

* Description    : Main program.

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

int main(void)

{

    u16 i;

#ifdef DEBUG

    debug();

#endif

    recv_ptr = 0;

   

    RCC_Configuration();

    GPIO_Configuration();

    NVIC_Configuration();

    DMA_Configuration();

    USART1_Configuration();

   

    printf("\r\nSystem Start...\r\n");

    printf("Initialling SendBuff... \r\n");

    for(i=0;i<SENDBUFF_SIZE;i++)

    {

        SendBuff = i&0xff;

    }

    printf("Initial success!\r\nWaiting for transmission...\r\n");

    //发送去数据已经准备好,按下按键即开始传输

    while(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3));

   

    printf("Start DMA transmission!\r\n");

   

    //这里是开始DMA传输前的一些准备工作,将USART1模块设置成DMA方式工作

    USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

    //开始一次DMA传输!

    DMA_Cmd(DMA1_Channel4, ENABLE);

   

    //等待DMA传输完成,此时我们来做另外一些事,点灯

    //实际应用中,传输数据期间,可以执行另外的任务

    while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)

    {

        LED_1_REV;      //LED翻转

        Delay();        //浪费时间

    }

    //DMA传输结束后,自动关闭了DMA通道,而无需手动关闭

    //下面的语句被注释

    //DMA_Cmd(DMA1_Channel4, DISABLE);

   

    printf("\r\nDMA transmission successful!\r\n");



   

    /* Infinite loop */

    while (1)

    {

    }

}



/*******************************************************************************

* Function Name  : 重定义系统putchar函数int fputc(int ch, FILE *f)

* Description    : 串口发一个字节

* Input          : int ch, FILE *f

* Output         :

* Return         : int ch

* 这个是使用printf的关键

*******************************************************************************/

int fputc(int ch, FILE *f)

{

    //USART_SendData(USART1, (u8) ch);

    USART1->DR = (u8) ch;

   

    /* Loop until the end of transmission */

    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)

    {

    }



    return ch;

}



/*******************************************************************************

* Function Name  : Delay

* Description    : 延时函数

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void Delay(void)

{

    u32 i;

    for(i=0;i<0xF0000;i++);

    return;

}



/*******************************************************************************

* Function Name  : RCC_Configuration

* Description    : 系统时钟设置

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void RCC_Configuration(void)

{

    ErrorStatus HSEStartUpStatus;



    //使能外部晶振

    RCC_HSEConfig(RCC_HSE_ON);

    //等待外部晶振稳定

    HSEStartUpStatus = RCC_WaitForHSEStartUp();

    //如果外部晶振启动成功,则进行下一步操作

    if(HSEStartUpStatus==SUCCESS)

    {

        //设置HCLK(AHB时钟)=SYSCLK

        RCC_HCLKConfig(RCC_SYSCLK_Div1);



        //PCLK1(APB1) = HCLK/2

        RCC_PCLK1Config(RCC_HCLK_Div2);



        //PCLK2(APB2) = HCLK

        RCC_PCLK2Config(RCC_HCLK_Div1);



        //FLASH时序控制

        //推荐值:SYSCLK = 0~24MHz   Latency=0

        //        SYSCLK = 24~48MHz  Latency=1

        //        SYSCLK = 48~72MHz  Latency=2

        FLASH_SetLatency(FLASH_Latency_2);

        //开启FLASH预取指功能

        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);



        //PLL设置 SYSCLK/1 * 9 = 8*1*9 = 72MHz

        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

        //启动PLL

        RCC_PLLCmd(ENABLE);

        //等待PLL稳定

        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

        //系统时钟SYSCLK来自PLL输出

        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

        //切换时钟后等待系统时钟稳定

        while(RCC_GetSYSCLKSource()!=0x08);





        /*

        //设置系统SYSCLK时钟为HSE输入

        RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);

        //等待时钟切换成功

        while(RCC_GetSYSCLKSource() != 0x04);

        */

    }



    //下面是给各模块开启时钟

    //启动GPIO

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | \

                           RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,\

                           ENABLE);

    //启动AFIO

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

    //启动USART1

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

    //启动DMA时钟

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

   

}







/*******************************************************************************

* Function Name  : GPIO_Configuration

* Description    : GPIO设置

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void GPIO_Configuration(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;



    //PC口4567脚设置GPIO输出,推挽 2M

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;

    GPIO_Init(GPIOC, &GPIO_InitStructure);



    //KEY2 KEY3 JOYKEY

    //位于PD口的3 4 11-15脚,使能设置为输入

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_11 | GPIO_Pin_12 |\

        GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_Init(GPIOD, &GPIO_InitStructure);



    //USART1_TX

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

   

    //USART1_RX

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_Init(GPIOA, &GPIO_InitStructure);



}







/*******************************************************************************

* Function Name  : NVIC_Configuration

* Description    : NVIC设置

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void NVIC_Configuration(void)

{

    NVIC_InitTypeDef NVIC_InitStructure;



#ifdef  VECT_TAB_RAM

    // Set the Vector Table base location at 0x20000000

    NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);

#else  /* VECT_TAB_FLASH  */

    // Set the Vector Table base location at 0x08000000

    NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);

#endif



    //设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    //串口接收中断打开   

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

}





/*******************************************************************************

* Function Name  : USART1_Configuration

* Description    : NUSART1设置

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void USART1_Configuration(void)

{

    USART_InitTypeDef USART_InitStructure;

   

    USART_InitStructure.USART_BaudRate = 9600;

    USART_InitStructure.USART_WordLength = USART_WordLength_8b;

    USART_InitStructure.USART_StopBits = USART_StopBits_1;

    USART_InitStructure.USART_Parity = USART_Parity_No;

    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;

    USART_Init(USART1, &USART_InitStructure);

   

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

   

    USART_Cmd(USART1, ENABLE);

}





void DMA_Configuration(void)

{

    DMA_InitTypeDef DMA_InitStructure;

    //DMA设置:

    //设置DMA源:内存地址&串口数据寄存器地址

    //方向:内存-->外设

    //每次传输位:8bit

    //传输大小DMA_BufferSize=SENDBUFF_SIZE

    //地址自增模式:外设地址不增,内存地址自增1

    //DMA模式:一次传输,非循环

    //优先级:中

    DMA_DeInit(DMA1_Channel4);

    DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;

    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;

    DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(DMA1_Channel4, &DMA_InitStructure);

}





打包的例子,是MDK下的工程,可供参考:)

点击此处下载 ourdev_545117.rar(文件大小:175K) (原文件名:USART_DMA.rar) 



本贴被 jjldc 编辑过,最后修改时间:2008-12-15,19:57:07.

出0入0汤圆

 楼主| 发表于 2008-12-15 20:03:22 | 显示全部楼层
呼,暂时就这么多了~~ 其他的有待探索~

出0入0汤圆

发表于 2008-12-15 20:10:31 | 显示全部楼层
不错的东西,适合我入门

出0入0汤圆

发表于 2008-12-15 22:11:38 | 显示全部楼层
谢谢分享。

出0入0汤圆

发表于 2008-12-15 22:15:09 | 显示全部楼层
厉害 顶!

出0入4汤圆

发表于 2008-12-15 22:38:08 | 显示全部楼层
不错,谢谢。非常佩服九九的学习能力~这么快就能搞这么多了

出0入0汤圆

发表于 2008-12-15 23:07:15 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2008-12-15 23:17:57 | 显示全部楼层
   强人一个,我搞了两个星期,还不如楼主几天

出0入0汤圆

发表于 2008-12-15 23:40:10 | 显示全部楼层
Mark

出0入0汤圆

发表于 2008-12-16 09:01:09 | 显示全部楼层
这么快就能搞这么多了,太厉害了,佩服!
头像被屏蔽

出0入0汤圆

发表于 2008-12-16 09:21:52 | 显示全部楼层
Cool .



九九?狗狗(广东话一样)?Google? 哈哈。。

出0入0汤圆

发表于 2008-12-16 09:51:52 | 显示全部楼层
顶顶九九

出0入0汤圆

发表于 2008-12-16 09:57:04 | 显示全部楼层
学习中,谢谢。

出0入0汤圆

发表于 2008-12-16 10:03:50 | 显示全部楼层
久久顶九九 

出0入46汤圆

发表于 2008-12-16 10:23:04 | 显示全部楼层
九九

出0入0汤圆

发表于 2008-12-16 10:43:45 | 显示全部楼层
不错啊,我也是上周再买的,现在只会点亮LED,最近比较忙,都没时间去学习。看来得加紧时间学习了

出0入50汤圆

发表于 2008-12-16 12:22:52 | 显示全部楼层
我的英蓓特板子都买了一年了,汗啊,实在没实际和精力去玩,又要拖到明年了......................

顶下楼主!

出0入0汤圆

发表于 2008-12-30 22:47:43 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-1-6 23:21:51 | 显示全部楼层
不错

出0入0汤圆

发表于 2009-1-7 22:54:23 | 显示全部楼层
第一个程序:按LZ的设置PC4口的输出频率应该是1KHZ,这样接个LED就看不出效果了。要想看到结果,程序得改点吧。我按如下修改,可以将PC4口的频率变成1HZ,这样就可以看出效果了,呵呵。我刚学,改得不知道对不,我用实验板试过效果可以。
        TIM_BaseInitStructure.TIM_Period = 10000;     //原来值为1000
        TIM_BaseInitStructure.TIM_RepetitionCounter = 100;       //原来值为0

出0入0汤圆

 楼主| 发表于 2009-1-7 23:19:58 | 显示全部楼层
楼上

按比例缩放下就可以了



肉眼看不出,示波器看阿

出0入0汤圆

发表于 2009-1-7 23:28:54 | 显示全部楼层
没示波器,呵呵。

不过按比例缩放一下就能用肉眼看出效果啦~

出0入0汤圆

发表于 2009-1-8 13:30:09 | 显示全部楼层
写的很详细

出0入0汤圆

发表于 2009-1-8 20:38:42 | 显示全部楼层
留个记号,学习中、、、

出0入0汤圆

发表于 2009-1-10 18:46:07 | 显示全部楼层
写的相当的好啊

出0入0汤圆

发表于 2009-1-17 08:50:56 | 显示全部楼层
好1

出0入0汤圆

发表于 2009-1-17 16:20:40 | 显示全部楼层
你的例子程序,都是精品啊.

出0入0汤圆

发表于 2009-1-20 14:32:36 | 显示全部楼层
不顶还是REN吗~~~顶~~~

出0入0汤圆

发表于 2009-1-21 11:34:47 | 显示全部楼层
楼主用的是IAR还是MDK啊?

出0入0汤圆

发表于 2009-1-21 15:02:05 | 显示全部楼层
例程是MDK3.24的,我下载试过了,ok

出0入0汤圆

发表于 2009-7-20 16:28:22 | 显示全部楼层
记号

出0入0汤圆

发表于 2009-7-20 17:55:15 | 显示全部楼层
感谢分享

出0入0汤圆

发表于 2009-7-21 13:56:52 | 显示全部楼层
99出品,必属珍品! 小弟收下啦。

出0入0汤圆

发表于 2009-7-21 16:08:42 | 显示全部楼层
jihao

出0入0汤圆

发表于 2009-7-23 14:05:46 | 显示全部楼层
写的简单明了,条理清晰,比keil的例子程序强多了

出0入0汤圆

发表于 2009-7-23 21:58:19 | 显示全部楼层
收下学习了,谢谢谢谢

出0入0汤圆

发表于 2009-7-28 12:59:09 | 显示全部楼层
谢谢 九九

出0入0汤圆

发表于 2009-8-3 15:23:04 | 显示全部楼层
向你学习,99

出0入0汤圆

发表于 2009-8-7 15:42:19 | 显示全部楼层
厉害喔,我看了快一个月的USB例程,最近才有点眉目!九九强人一个!

出0入0汤圆

发表于 2009-8-11 02:00:21 | 显示全部楼层
九九,的确是很强,也很谦虚。

才子一个。

支持一下。

出0入0汤圆

发表于 2009-8-12 15:36:33 | 显示全部楼层
感谢分享。
我用的也是万利的199的那个开发板。但是昨天在仿真的时候提示“can't halt the core”
是什么原因?

出0入0汤圆

发表于 2009-9-25 22:48:42 | 显示全部楼层
收藏

出0入0汤圆

发表于 2009-9-26 09:22:55 | 显示全部楼层
谢谢分享!
学习。。。

出0入0汤圆

发表于 2009-9-26 13:21:16 | 显示全部楼层
mark,
支持99

出0入0汤圆

发表于 2009-9-26 16:34:47 | 显示全部楼层
强大!佩服!
顺便问一句,keil里的随机函数是怎么写的??

出0入0汤圆

发表于 2009-10-26 21:06:51 | 显示全部楼层
呵呵,九九真厉害,赞一个~~~~

出0入0汤圆

发表于 2009-10-27 20:45:54 | 显示全部楼层
九九真厉害!赞一个!谢谢啦~~~

出0入0汤圆

发表于 2009-10-28 11:39:09 | 显示全部楼层
mark
支持下

出0入0汤圆

发表于 2009-10-28 12:04:19 | 显示全部楼层
mark
支持下

出0入0汤圆

发表于 2009-10-28 12:15:43 | 显示全部楼层
mark.
楼主太强了

出0入0汤圆

发表于 2009-10-28 16:30:54 | 显示全部楼层
mark  
支持下

出0入0汤圆

发表于 2009-10-28 22:06:56 | 显示全部楼层
不错GG.

出0入0汤圆

发表于 2009-10-29 20:14:07 | 显示全部楼层
牛人一个!太强了!

出0入0汤圆

发表于 2009-11-8 21:09:57 | 显示全部楼层
yes。。。。。。。。。。。。

出0入0汤圆

发表于 2009-11-12 14:53:39 | 显示全部楼层
好好学习

出0入0汤圆

发表于 2009-12-3 12:04:32 | 显示全部楼层
再顶

出0入0汤圆

发表于 2009-12-9 09:38:30 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-12-9 19:55:09 | 显示全部楼层
开眼了。支持!

出0入0汤圆

发表于 2010-2-3 15:37:51 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2010-4-30 09:32:57 | 显示全部楼层
楼主辛苦,正在看定时器,很是受用。

出0入0汤圆

发表于 2010-4-30 13:55:57 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-30 14:54:46 | 显示全部楼层
学习

出0入0汤圆

发表于 2010-4-30 15:18:57 | 显示全部楼层
前来学习

出0入0汤圆

发表于 2010-5-6 10:21:14 | 显示全部楼层
强烈关注~~~

出0入0汤圆

发表于 2010-5-6 12:37:35 | 显示全部楼层
使劲顶顶

出0入46汤圆

发表于 2010-5-6 13:53:03 | 显示全部楼层

出0入0汤圆

发表于 2010-5-6 18:46:04 | 显示全部楼层

出0入0汤圆

发表于 2010-5-18 16:37:46 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-5-20 15:32:56 | 显示全部楼层
楼主厉害

出0入0汤圆

发表于 2010-5-31 13:05:33 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-8-19 16:54:15 | 显示全部楼层
俺也先顶下

出0入0汤圆

发表于 2010-8-19 21:20:04 | 显示全部楼层
感谢分享.....

出0入0汤圆

发表于 2010-8-20 07:03:22 | 显示全部楼层
在我印象中,九九应该比我早上手STM32,呵呵。做步进电机驱动的时候,应该参照过九九的定时器代码。表示谢谢

出0入0汤圆

发表于 2010-8-20 10:04:10 | 显示全部楼层
楼主太强了,顶一下!!!

出0入0汤圆

发表于 2010-9-16 16:27:44 | 显示全部楼层
顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶,期待续集!!!!!!!

出0入0汤圆

发表于 2010-10-15 21:05:59 | 显示全部楼层
很好很强大

出0入0汤圆

发表于 2010-10-21 13:53:09 | 显示全部楼层
赞一个,大家都向99学习

出350入8汤圆

发表于 2010-10-21 15:13:44 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-10-24 13:08:24 | 显示全部楼层
谢谢 下完楼

出0入0汤圆

发表于 2010-10-24 21:27:14 | 显示全部楼层
谢谢,学习

出0入0汤圆

发表于 2010-10-25 11:25:45 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-10-28 22:39:44 | 显示全部楼层
up!!!!!!!!!!

出0入0汤圆

发表于 2010-10-29 01:36:52 | 显示全部楼层
好东西,标记一下

出0入0汤圆

发表于 2010-10-29 14:24:49 | 显示全部楼层
支持一下,俺也打算入这个板子,不过看了楼主的这么多介绍反而有点害怕了

出0入0汤圆

发表于 2010-11-23 15:08:21 | 显示全部楼层
适合我这菜鸟,感谢楼主!

出0入0汤圆

发表于 2010-12-1 20:56:55 | 显示全部楼层
xuexi,支持一下

出0入0汤圆

发表于 2010-12-1 22:00:19 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-4-15 11:27:34 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-4-15 17:11:48 | 显示全部楼层
后满一定对我用出嘟嘟u

出0入0汤圆

发表于 2011-5-6 14:17:46 | 显示全部楼层

出0入0汤圆

发表于 2011-5-7 00:03:41 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-8 09:43:39 | 显示全部楼层
九九好谦虚啊

出0入0汤圆

发表于 2011-5-9 11:17:38 | 显示全部楼层
mark!

出0入0汤圆

发表于 2011-5-9 14:14:13 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-30 20:42:30 | 显示全部楼层
Mark!

出0入0汤圆

发表于 2011-6-22 17:55:55 | 显示全部楼层
mark
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-5 09:27

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表