Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

I needed help with running a stepper motor using Codewarrior and a Dragon 12 boa

ID: 3603044 • Letter: I

Question

I needed help with running a stepper motor using Codewarrior and a Dragon 12 board.

I have the keypad code, LCD code, and a main file which you can use to test the other 2 files, but I am struggling on how to write a C code to interact with the stepper motor and implement that into the main file.

[Main.C]

//The project has two device drivers: one for the keypad and other for the LCD

//You need to write your a device driver that will control the stepper motor

#include <hidef.h> /* common defines and macros */

#include "derivative.h" /* derivative-specific definitions */

#include"Keypad.h"

#include "LCD.h"

#define EDIT_COL 810

char buf[8];

int bufp;

void just_demo(void);

void delay_ms(unsigned);

void main(void) {

char k;

int i;

  

Keypad_init();

LCD_init();  

  

  

LCD_setCursor(0,0);

LCD_print("Enter Pos:");

  

LCD_setCursor(1,0);

LCD_print("Curr Pos:");

LCD_setCursor(1,EDIT_COL);

LCD_print("Stop."); // assume stopped & at pos = 0

  

  

for(;;) {

  

//read the command position from user...

  

//first put the cursor there so that we print as user is entering keys...

LCD_setCursor(0,EDIT_COL);

  

//next: keep reading until user press '#' which is key E in this board

//store in buffer & display on LCD what user is entering

//we will assume correct entry

  

bufp = 0;

k = Keypad_wait_keypress();

while( k!= 0x0E && bufp < 8 ){

buf[bufp++] = k; // store pressed key in buffer

LCD_putchar(k+'0'); //display as user is entering

  

Keypad_wait_keyup(); //wait until user release this key

  

k = Keypad_wait_keypress(); //read next key and back to check...   

}

  

  

//your code should begin here...

//buf has the commanded position and bufp is their count

//move the stepper to that angle given its current position.....

  

  

just_demo();

  

  

//The stepper should have reached its commanded pos now....

//display curr pos

LCD_setCursor(1,EDIT_COL);

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

LCD_putchar(buf[i]+'0');

  

//erase old commanded pos

LCD_setCursor(0,EDIT_COL);

LCD_print(" ");

  

}

}

void just_demo(){

int i;

  

for( i = 0; i < 5 ; i++){

LCD_setCursor(1, EDIT_COL);

LCD_print("Mot...");

delay_ms(500);

LCD_setCursor(1, EDIT_COL);

LCD_print(" ");

delay_ms(500);

}

  

}

/*----------------------------------

;

; delay for 1 us

*/

void delay_1us(){

asm{

  

PSHX

LDX #4   

L1: DBNE X,L1

PULX   

  

}

}

/*------------------------------------------------

; delay_us

------------------------------------------------*/

void delay_us(unsigned int us ){

asm{   

pshd

dd: JSR delay_1us

DBNE D, dd

puld

  

}

}

/*-------------------

; delay_ms

;----------------------------- */

void delay_ms(unsigned int ms){

asm{

pshd

; 2 clock cycles

PSHX ; 2 clock cycles

OutLoop:

LDX #7993 ; 2

InLoop:

DBNE X, InLoop ; 3/3 ( 3 cycles both ways)

DBNE D, OutLoop ; 3/3

PULX ; 3

puld

}

}

[Keypad.C]


#include "keypad.h"
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */

void delay_us(unsigned int);
void delay_ms(unsigned int);


// Keypad Device Driver

  
  
int col, row;
  

/*-------------------------------------------------------------
; Keypad_init
; The Keypad on the dragon12 board is connected to port A
; configure port A pins as input & enable the internal pullup registers on them
-----------------------------------------------------------------*/


void Keypad_init(){
  
DDRA = 0;
PUCR |= 1 ; //Pull-Up Port A Enable   
PORTA = 0; //PAx would be driven low once we change its direction in DDRAx to be an output pin

}


/*---------------------------------------------------------------------------
; Keypad_non_scan
; returns the hex code of the currently pressed key, or return $10 if all keys are up
;
; This function does not scan all rows and columns. Instead it accesses the key (if any) in just two quick steps:
; 1. Makes all rows outputs (driven low) and cols as inputs.
; It then reads the cols from PORTA
; 2. It changes the direction of rows as inputs and cols as outputs (driven low).
; It then reads rows from PORTA
; with the row and the col, we do some lookup to find the pressed key or $10

;
----------------------------------------------------------*/
//rows:PORTA[7:4] cols:PORTA[3:0]
char Keypad_non_scan(){
extern char keys[][5];
extern char row_col_tab[];
  
// rows are out, cols are in  
DDRA = 0xF0;
// wait few cycles as noted in the manual   
delay_us(5);

  
//get col: $xE(leftmost column), $xD, $xB, $x7, or $xF if no press
col = PORTA & 0x0F;
  
  
  
//rows are ins, cols are outs  
DDRA = 0x0F;
//wait few cycles as noted in the manual
delay_us(5);
  
//get row: $Ex (first row), $Dx, $Bx, $7x, or $Fx if no press
row = (PORTA >> 4) &0x0F;
  
//map them into values between 0 & 4
row = row_col_tab[row]; // now could be any value from 0 through 4
col = row_col_tab[col]; // so does col
  
  
return keys[row][col];
}


/*------------------------------------------------------------------------------------------
; Keypad_read;
; This is a debounced function
; It keeps sampling the keypad every 5ms until the three samples are same
;
; return the pressed hex key, or $10 if all keys are up (debounced)
-------------------------------------------------*/

char Keypad_read(){
char k[3];
do{
  
//first sample
k[0]=Keypad_non_scan();
delay_ms(5);
  
//2nd sample   
k[1]=Keypad_non_scan();
delay_ms(5);
  
//third sample
k[2]=Keypad_non_scan();
}while(k[0] != k[1] || k[1]!=k[2]); // keep sampling until the 3 samples are same
  
  
//either the pressed key or 0x10 (debounced)
return k[0];
}

/*----------------------------------------------------   
; Keypad_wait_keypress:
; wait until a key is pressed and return
--------------------------------------------------*/
char Keypad_wait_keypress(){
char key;

for( key = Keypad_read() ; key ==0x10; key = Keypad_read() ) //keep trying until a key is pressed
;
return key;
}

/*--------------------------------------------------
; Keypad_wait_keyup:
; wait until all keys are up and then return
-------------------------------------------------------*/

void Keypad_wait_keyup(){
while( Keypad_read() != 0x10 ) //keep trying until all keys are up
;
}

//---------------------------------------
// lookup the key by row & col   
//col 0 1 2 3 4
// PA0 PA1 PA2 PA3
//
// row
char keys[][5]={
{0x01, 0x02, 0x03, 0x0A ,0x10}, // 0 PA4
{0x04, 0x05, 0x06, 0x0B ,0x10}, // 1 PA5
{0x07, 0x08, 0x09, 0x0C ,0x10}, // 2 PA6
{0x0F, 0x00, 0x0E, 0x0D ,0x10}, // 3 PA7
{0x10, 0x10, 0x10, 0x10, 0x10} // 4
};

/*----------------------------------------------------------
; lookup the row or the col by the value that is read from PORTA during Keypad_non_scan
;
; when a key is detected, the 4-bit value read from PORTA could be 7, B, D, E. Otherwise, it is F
; We map the detected 4-bit value into row or col:0-3. F will be mapped into 4
*/
char row_col_tab[]={
  
4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 2, 4, 1, 0, 4
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
};
  

[LCD.C]


#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */

#include "LCD.h"

void delay_ms(unsigned), delay_us(unsigned);

#define E 2
#define RS 1

void lcd_send_nibble(char c);
void lcd_send_data(unsigned char data);
void lcd_send_cmd(unsigned char cmd);

/*----------------------------------------------------------
; LCD connections to MCU
; LCD MC9S12DG256x
; === ============
; RS <----> PK0 RS = 0 for lcd commands transfer, RS=1 for lcd data transfer
;   
; E <----> PK1 a high plus must be generated on E when writing to LCD
;   
; D4 <----> PK2
; D5 <----> PK3
; D6 <----> PK4
; D7 <----> PK5
; R/W pin on LCD is connected to ground in this board (Write Only connection)

*/


//; initalize the LCD
// check HD44780 datasheet
void LCD_init(){
  
  
  
delay_ms(15); //wait 15ms (datasheet)
  
DDRK = 0xFF; // config port K as an output port.
  
  
//send 3 as a nibble first time (datasheet)
lcd_send_nibble(3);   
delay_us(4100); //wait 4.1 ms (datasheet)
  
  
//send 3 as a nibble second time (datasheet)
lcd_send_nibble(3);   
delay_us(100); //wait 100us (datasheet)
  
  
//send 3 as a nibble 3rd time (datasheet)
lcd_send_nibble(3);
  
//send 2 as a nibble 4th time (datasheet)
lcd_send_nibble(2);
  
  
  
  
//start configuration now
  
  
// function set: 0 0 1 DL N F x x
// ;(DL= 0 for 4 bit mode, N=1 for 2lines, F=0 for 5x7)
  
lcd_send_cmd(0x28); // LCD is connected as 4-bit mode interface to port K

  
  
// display Off: 0 0 0 0 1 D C B
// D = 0 C =0 B = 0
lcd_send_cmd(0x08);

  
LCD_clear();   
  
//display On: 0 0 0 0 1 D C B
//D = 1 C =0 B = 0
//display on, cursor off, no blinking
  
lcd_send_cmd(0x0C);

  
  
//entry mode: 0 0 0 0 0 1 I/D S
// I/D = 1 cursor increment, S = 0 to disable display shift
lcd_send_cmd(0x06);

}



//send lower nibble [3:0] out to LCD
void lcd_send_nibble(char c){
  
c &= 0x0F;
c <<= 2; // adjust for portk[5:2]
  
//drive port K pins and generate a 1us pulse on E
  
PORTK = c; //E = 0, RS = 0 PORTK[5:2] = data[5:2]   
PORTK |= E; //E = 1 , RS =0   
PORTK &= ~E; //E = 0 , RS =0   
  
  
delay_us(40); //wait 40us (datasheet)
  
}


// send 8-bit command to LCD
void lcd_send_cmd(unsigned char cmd){
char save = cmd;
  
  
//send upper nibble first   
cmd &= 0xF0;
cmd >>= 2; // adjust for portk [5:2]
PORTK = cmd; // E = 0, RS = 0 PORTK[5:2] = data[5:2]
  
//generate a pulse on E
PORTK |=E; // E = 1 , RS =0   
PORTK &=~E; // E = 0 , RS =0   
delay_us(40);
  
  
//send lower nibble next   
cmd = save;
cmd &= 0x0F;
cmd <<= 2; // adjust for portk[5:2]
  
PORTK = cmd; // E = 0, RS = 0 PORTK[5:2] = data[5:2]
  
//generate a pulse on E
PORTK |=E; // E = 1 , RS =0   
PORTK &=~E; // E = 0 , RS =0   
delay_us(40);
  
}
  
  

// send 8-bit data to LCD
// same as lcd_send_cmd except RS must be 1

void lcd_send_data(unsigned char data){
char save = data;
//send upper nibble first   
  
data &=0xF0;
data >>= 2;
data |= RS;
PORTK = data; // E = 0 , RS = 1 PORTK[5:2] = data[5:2]
  
//generate a pulse on E
PORTK |=E; // E = 1 , RS =1   
PORTK &=~E; // E = 0 , RS =1   
delay_us(40);


//send lower nibble next
data = save;
data &=0x0F;
data <<= 2;
data |= RS;
PORTK = data; // E = 0 , RS = 1 PORTK[5:2] = data[5:2]
  
//generate a pulse on E
PORTK |=E; // E = 1 , RS =1   
PORTK &=~E; // E = 0 , RS =1   
delay_us(40);
  
  
  
}
  

//put the cursor at row and col. LCD with 2x16
//row: 0 or 1
//col: 0 through 15
void LCD_setCursor(int row, int col){
static char A[]={0,0x40};
row &=1;
col &=0x0F;
lcd_send_cmd((A[row]|0x80) + col);
}
  
  

//Clear the LCD and send cursor home
void LCD_clear(){
  
//$01 Clear command (datasheet)
lcd_send_cmd(0x01);
  
//wait 1.6ms (datasheet)
delay_us(1600);
  
//$02 Cursor Home command (datasheet)
lcd_send_cmd(0x02);
  
//wait 1.6ms (datasheet)
delay_us(1600);
}
  
  

// print a character on LCD at the current cursor pos

void LCD_putchar(char ch){
lcd_send_data(ch);
}
  

//print a string on LCD
void LCD_print(char *s){
while(*s)
LCD_putchar(*s++);
}

  

Explanation / Answer

#include <hidef.h> /* common defines and macros */

#include "derivative.h" /* derivative-specific definitions */

#include"Keypad.h"

#include "LCD.h"

#define EDIT_COL 810

char buf[8];

int bufp;

void just_demo(void);

void delay_ms(unsigned);

void main(void) {

char k;

int i;

  

Keypad_init();

LCD_init();  

  

  

LCD_setCursor(0,0);

LCD_print("Enter Pos:");

  

LCD_setCursor(1,0);

LCD_print("Curr Pos:");

LCD_setCursor(1,EDIT_COL);

LCD_print("Stop."); // assume stopped & at pos = 0

  

  

for(;;) {

  

//read the command position from user...

  

//first put the cursor there so that we print as user is entering keys...

LCD_setCursor(0,EDIT_COL);

  

//next: keep reading until user press '#' which is key E in this board

//store in buffer & display on LCD what user is entering

//we will assume correct entry

  

bufp = 0;

k = Keypad_wait_keypress();

while( k!= 0x0E && bufp < 8 ){

buf[bufp++] = k; // store pressed key in buffer

LCD_putchar(k+'0'); //display as user is entering

  

Keypad_wait_keyup(); //wait until user release this key

  

k = Keypad_wait_keypress(); //read next key and back to check...   

}

  

  

//your code should begin here...

//buf has the commanded position and bufp is their count

//move the stepper to that angle given its current position.....

  

  

just_demo();

  

  

//The stepper should have reached its commanded pos now....

//display curr pos

LCD_setCursor(1,EDIT_COL);

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

LCD_putchar(buf[i]+'0');

  

//erase old commanded pos

LCD_setCursor(0,EDIT_COL);

LCD_print(" ");

  

}

}

void just_demo(){

int i;

  

for( i = 0; i < 5 ; i++){

LCD_setCursor(1, EDIT_COL);

LCD_print("Mot...");

delay_ms(500);

LCD_setCursor(1, EDIT_COL);

LCD_print(" ");

delay_ms(500);

}

  

}

/*----------------------------------

;

; delay for 1 us

*/

void delay_1us(){

asm{

  

PSHX

LDX #4   

L1: DBNE X,L1

PULX   

  

}

}

/*------------------------------------------------

; delay_us

------------------------------------------------*/

void delay_us(unsigned int us ){

asm{   

pshd

dd: JSR delay_1us

DBNE D, dd

puld

  

}

}

/*-------------------

; delay_ms

;----------------------------- */

void delay_ms(unsigned int ms){

asm{

pshd

; 2 clock cycles

PSHX ; 2 clock cycles

OutLoop:

LDX #7993 ; 2

InLoop:

DBNE X, InLoop ; 3/3 ( 3 cycles both ways)

DBNE D, OutLoop ; 3/3

PULX ; 3

puld

}

}

[Keypad.C]


#include "keypad.h"
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */

void delay_us(unsigned int);
void delay_ms(unsigned int);


// Keypad Device Driver

  
  
int col, row;
  

/*-------------------------------------------------------------
; Keypad_init
; The Keypad on the dragon12 board is connected to port A
; configure port A pins as input & enable the internal pullup registers on them

void LCD_init(){
  
  
  
delay_ms(15); //wait 15ms (datasheet)
  
DDRK = 0xFF; // config port K as an output port.
  
  
//send 3 as a nibble first time (datasheet)
lcd_send_nibble(3);   
delay_us(4100); //wait 4.1 ms (datasheet)
  
  
//send 3 as a nibble second time (datasheet)
lcd_send_nibble(3);   
delay_us(100); //wait 100us (datasheet)
  
  
//send 3 as a nibble 3rd time (datasheet)
lcd_send_nibble(3);
  
//send 2 as a nibble 4th time (datasheet)
lcd_send_nibble(2);
  
  
  
  
//start configuration now
  
  
// function set: 0 0 1 DL N F x x
// ;(DL= 0 for 4 bit mode, N=1 for 2lines, F=0 for 5x7)
  
lcd_send_cmd(0x28); // LCD is connected as 4-bit mode interface to port K

  
  
// display Off: 0 0 0 0 1 D C B
// D = 0 C =0 B = 0
lcd_send_cmd(0x08);

  
LCD_clear();   
  
//display On: 0 0 0 0 1 D C B
//D = 1 C =0 B = 0
//display on, cursor off, no blinking
  
lcd_send_cmd(0x0C);

  
  
//entry mode: 0 0 0 0 0 1 I/D S
// I/D = 1 cursor increment, S = 0 to disable display shift
lcd_send_cmd(0x06);

}



//send lower nibble [3:0] out to LCD
void lcd_send_nibble(char c){
  
c &= 0x0F;
c <<= 2; // adjust for portk[5:2]
  
//drive port K pins and generate a 1us pulse on E
  
PORTK = c; //E = 0, RS = 0 PORTK[5:2] = data[5:2]   
PORTK |= E; //E = 1 , RS =0   
PORTK &= ~E; //E = 0 , RS =0   
  
  
delay_us(40); //wait 40us (datasheet)
  
}


// send 8-bit command to LCD
void lcd_send_cmd(unsigned char cmd){
char save = cmd;
  
  
//send upper nibble first   
cmd &= 0xF0;
cmd >>= 2; // adjust for portk [5:2]
PORTK = cmd; // E = 0, RS = 0 PORTK[5:2] = data[5:2]
  
//generate a pulse on E
PORTK |=E; // E = 1 , RS =0   
PORTK &=~E; // E = 0 , RS =0   
delay_us(40);
  
  
//send lower nibble next   
cmd = save;
cmd &= 0x0F;
cmd <<= 2; // adjust for portk[5:2]
  
PORTK = cmd; // E = 0, RS = 0 PORTK[5:2] = data[5:2]
  
//generate a pulse on E
PORTK |=E; // E = 1 , RS =0   
PORTK &=~E; // E = 0 , RS =0   
delay_us(40);
  
}
  
  

// send 8-bit data to LCD
// same as lcd_send_cmd except RS must be 1

void lcd_send_data(unsigned char data){
char save = data;
//send upper nibble first   
  
data &=0xF0;
data >>= 2;
data |= RS;
PORTK = data; // E = 0 , RS = 1 PORTK[5:2] = data[5:2]
  
//generate a pulse on E
PORTK |=E; // E = 1 , RS =1   
PORTK &=~E; // E = 0 , RS =1   
delay_us(40);


//send lower nibble next
data = save;
data &=0x0F;
data <<= 2;
data |= RS;
PORTK = data; // E = 0 , RS = 1 PORTK[5:2] = data[5:2]
  
//generate a pulse on E
PORTK |=E; // E = 1 , RS =1   
PORTK &=~E; // E = 0 , RS =1   
delay_us(40);
  
  
  
}
  

//put the cursor at row and col. LCD with 2x16
//row: 0 or 1
//col: 0 through 15
void LCD_setCursor(int row, int col){
static char A[]={0,0x40};
row &=1;
col &=0x0F;
lcd_send_cmd((A[row]|0x80) + col);
}