Detecting rising and falling temperature C - c

I'm trying to detect rising and falling temperatures using PIC16F877A MCU and two DS8B20 sensors. I'm facing with problems when I try to detect temperature falling. Here is my code what am I trying to do:
#include "main.h"
void main() {
//Turn on LCD backlight
output_high(PIN_D7);
// Initialize LCD module
lcd_init();
float Threshold_Value = 30; // Temperature threshold value
while (TRUE) {
Show_User_Info();
delay_ms(10);
Read_Sensors();
// Starting to read user button values
User_Buttons();
delay_ms(20); // Minimum amount of time to read user button values
// Starting to compare user set temperature value and upper sensor temperature read value.
Compare_Upper_Temp();
delay_ms(20);
//================================
// Checking, if the MCU pin connected to pump is high. If yes - do the waiting 'animation'
if (input(PIN_B5)) {
while(temp > Threshold_Value);
{
Bottom_Waiting_Animation();
}
// Experimenting....
// break;
// continue;
}
if (input(PIN_B5)) {
while(temp < Threshold_Value);
{
Bottom_Waiting_Animation();
}
// break;
}
// If the set temp is less than threshold - turn the pump off.
if (temp < Threshold_Value) {
input(PIN_B5) == 0;
}
}
}
When the pump is switched on, I need to wait until second sensor reaches threshold value (30C), after that I need to 'detect' when that temperature starts to drop from that 30C. This code which I uploaded 'works' only with one While(temp > Threshold_Value) loop. But when I insert the next one under it while(temp < Threshold_Value), MCU jumps in undefined area and gets stuck. This task sounds pretty easy, but I tried lots of different ways to solve this problem. Maybe one of the problem reasons could be multiple while loops?

Don't use a semicolon after the while condition.
Replace
while (condition);
{
... looped code ...
}
with
while (condition)
{
.... looped code ...
}
This is one reason I like to put open braces at the end of the condition (as you do in your if statements): it helps to see the obnoxious accidental semicolon.

Related

is there a way to wait for something without interrupt the execution of other code?

i have to write a function that, by calling it only a single time, have to:
turn on an output pin
the pin stays high for 200mS
at the end of the timer the pin need to be low again.
the pin stays low for 200mS
at the end of the timer the function can be called again.
to turn on and off an output pin I already have wrote and tested the funcions:
outOn(pin_id);
outOff(pin_id);
now, i am trying to write the function that does the above mentioned actions and this is what l've come out with so far:
void outOnT02(enum e_outs ou){
outOn(ou);
gu_RegTim.BTime[BTIM_FUNCT].Timer = O_SEC01*2;
if(gu_RegTim.BTime[BTIM_FUNCT].b.Stato == O_EndTimer) {
outOff(ou);
}
}
the function is named outOnT02 because:
it is an output;
after calling it, the pin became high;
T02 because the pin stays high for 0.2 Seconds.
outOn(ou); makes the pin go high,
outOff(ou); makes the pin go low,
gu_RegTim.BTime[BTIM_FUNCT].Timer = O_SEC01*2;
starts a 200mS timer,
and gu_RegTim.BTime[BTIM_FUNCT].b.Stato == O_EndTimer is true when the timer has run out.
it works but, as you can tell, I have to put it in a cycle otherwise gu_RegTim.BTime[BTIM_FUNCT].b.Stato == O_EndTimer will never be true and so,the pin will stay high forever.
this is where i am stuck. i can't use a SLEEP(200); because i can't interrupt the execution of the code.
the language is C, the ide is MPLAB X IDE v6.00, the compiler is XC8 v2.31 and the cpu is a PIC16F15355.
This post is a little old but it is worth to answer since it is both a good question and a common problem. Now this problem is very common in embedded world when we develop applications that has to run on only one CPU. Hence there is no real parallelism in the workflow. Also since the application will not run on top of any OS, there will be no scheduler, no timers, no threads etc. Especially in small scaled microcontrollers there is no way to run many of the true RTOSs.
But this shouldn't be an obstacle for developing applications that runs tasks concurrently. We can develop an application using some tricks so that it runs the tasks concurrently and behave as a small OS. Running concurrently means that no task blocks the CPU using busy waiting checks or something alike but we block a task that needs to wait some event to occur.
When we block a task, the specific data and the next execution point on that task must be preserved so that it can continue from where it should in the next execution. Knowing what we need to preserve helps us to create a thread-like structures that executes until it has to wait some event to occur (eg. time delay). When it has to wait (means that it will be blocked) the next state of it must be preserved and it exits to give the control to the CPU so that it executes other tasks.
When we need to deal with periodic tasks as in the question, it is relatively easier to implement without blocking the CPU execution and meanwhile handle other tasks. Moreover no interrupt usage needed for this type of tasks unless the tasks are extremely time sensitive.
Well, enough with the story part, let's get into it. I will base the examples on the OP's output flashing problem. However the same techniques can be applied for other situations like I/O events, hardware events etc.
Let's sum up the requirement briefly, we have a task that runs atomically. That is, when it is called it must run to completion so that it can be called again (this is what I understand from the OP's requirement):
Turns on an output pin for 200ms
Then turns off the pin for 200ms
Once turned off and 200ms time has elapsed it can be executed again.
Note Some functions in this example are not implemented since they can be application or microcontroller specific.
Task-like Functions
Let's assume we want to schedule the following two task-like functions each of which keeps track of its execution continuation points.
The static cp variables are declared in each function so that they remember where to continue whenever they are called. The content of cp variable will not be destroyed by the compiler when the function returns since we declare it as static. The cp needs to be updated upon the expected events occur in order to proceed to the next step whenever it is called.
Note that in outputTask, the call source must be known to control its atomic behaviour. Since the requirement for this task is that once it triggered or called, it must run to completion. So we have to know where the task is called from, in order it to decide what to do on each call. If it has been triggered from another task, it can't be triggered anymore until it completes its flashing prosess. If it is called from the scheduler (main loop) it knows it is a periodic call and will keep track of the time. This control is achieved using a parameter called periodic. When it is called from the scheduler this parameter must be set to 1, and 0 for the calls other than the scheduler.
/*
* This task-like function performs what the OP wants to achieve
*/
void outputTask(unsigned char periodic) {
static unsigned char cp = 0; // Continuation Point holder
static unsigned char currentMillis;
/*
* Check whether it is a periodic call or a new output signal call.
* If it is a periodic call and signalling has been initialized,
* proceed for time keeping.
* If it is a new signalling call and the task hasn't completed yet,
* simply ignore and return.
*/
if(!periodic && cp != 0) {
return;
}
switch(cp) {
case 0:
outOn(pin_id); // Turn on the output
cp = 1; // Next execution point
currentMillis = 200; // Load the 200ms counter for time keeping
break;
case 1:
currentMillis--;
if(currentMillis == 0) {
// 200ms time for output high has elapsed, proceed to next step
outOff(pin_id); // Turn off the output
currentMillis = 200; // Reload the counter value
cp = 2; // Proceed to the next step
}
break;
case 2:
currentMillis--;
if(currentMillis == 0) {
// 200ms time for output low has elapsed, proceed to next step
cp = 0; // Last step is done, reset the state for new calls
}
break;
default:
// For anything else, reset the task state to the initials
cp = 0 // Reset the task state to zero so that it accepts new calls
}
}
/*
* Let's say this task will wait for a button press event and will
* trigger the outputTask upon the event occurs
*/
void outputTriggerTask() {
static unsigned char cp = 0;
static unsigned char currentMillis;
switch(cp) {
case 0:
if(isButtonPressed()) { // Platform specific function
// A button press has been detected, debounce first
currentMillis = 50;
cp = 1; // Next step, check for the elapsed time
}
else {
break;
}
case 1:
currentMillis--;
if(currentMillis == 0) {
// Check whether the button press is consistent
if(isButtonPressed()) {
// Yes still consistent, handle the button press by triggering the output task
outputTask(0); // Not a periodic call
cp = 2; // Next step is to check whether button is released
}
else {
cp = 0; // Reset the task state
}
}
break;
case 2:
if(isButtonReleased()) { // Platform specific function
currentMillis = 50; // Reload the time counter
cp = 3;
}
else {
break;
}
case 3:
currentMillis--;
if(currentMillis == 0) {
// Check whether the button release is consistent
if(isButtonReleased()) {
// Yes still consistent, handle the button release if needed
cp = 0; // Reset the task to its initial state
}
}
break;
default:
cp = 0; // Reset to initials
}
}
Scheduling Approches
The following approches are for non RTOS small embedded systems. They are suitable for wide range of 8-bit microcontrollers.
Approach 1 - Create Delay Based Timebase to Schedule Tasks
Scheduling using CPU blocking delay is suitable for hobby and educational purposes while it is not suitable for real projects. This example uses a platform specific delay_ms function (or can be a macro) to create a 1ms heartbeat for the application so that the tasks can keep track of time.
void main(void) {
systemInit(); // Platform specific function
// maybe some more init functions go here
// Application's infinite scheduler loop
while(1) {
// The first thing we do is to create a 1ms timebase using delay.
// This is the heartbeat for the application
delay_ms(1000); // Platform specific function
// 1ms has elapsed check the tasks
outputTriggerTask(); // Check whether any button press event has occured
outputTask(1); // It is a periodic call for the output task
// Maybe more tasks go here...
}
}
Approach 2 - Create Hardware Timer Based Timebase
void main(void) {
systemInit(); // Platform specific function
// Setup a hardware timer for 1ms overflow without interrupt
initTimerForOneMs(); // Platform specific function
// maybe some more init functions go here
// Application's infinite scheduler loop
while(1) {
// Wait for the timer to overflow
while(!isTimerOverflow()) // Platform specific function
;
// Timer has overflowed, reload and check tasks
reloadTimer(); // Platform specific function
// 1ms has elapsed check the tasks
outputTriggerTask(); // Check whether any button press event has occured
outputTask(1); // It is a periodic call for the output task
// Maybe more tasks go here...
}
}
Approach 3 Put the Processor to Sleep for 1ms Timebase
void main(void) {
systemInit(); // Platform specific function
// maybe some more init functions go here
// Application's infinite scheduler loop
while(1) {
// Put the Processor to sleep along with a watchdog timer to wake it up
clearWatchdogTimer(); // Platform specific function
sleep(); // Platform specific function
// CPU slept for 1ms and woke up, handle the periodic tasks
outputTriggerTask(); // Check whether any button press event has occured
clearWatchdogTimer(); // Platform specific function
outputTask(1); // It is a periodic call for the output task
clearWatchdogTimer(); // Platform specific function
// Maybe more tasks go here...
}
}
And Last But not Least Time Checking Approach
In this approach the tasks will be keeping the time by checking better say comparing the elapsed time to the desired time to delay tasks without blocking the CPU. For this, we will need to use a free running timer. This will be like the millis function of the Arduino API.
Rewriting the Tasks for the Time Checking Approach
/*
* This task-like function performs what the OP wants to achieve
*/
void outputTask(unsigned char periodic) {
static unsigned char cp = 0; // Continuation Point holder
static unsigned short currentMillis; // 16 bit millisecond holder
/*
* Check whether it is a periodic call or a new output signal call.
* If it is a periodic call and signalling has been initialized,
* proceed for time keeping.
* If it is a new signalling call and the task hasn't completed yet,
* simply ignore and return.
*/
if(!periodic && cp != 0) {
return;
}
switch(cp) {
case 0:
outOn(pin_id); // Turn on the output
cp = 1; // Next execution point
currentMillis = getCurrentMillis(); // Platform specific function
break;
case 1:
if(getCurrentMillis() - currentMillis >= 200) {
// 200ms time for output high has elapsed, proceed to next step
outOff(pin_id); // Turn off the output
currentMillis = getCurrentMillis(); // Reload the counter value
cp = 2; // Proceed to the next step
}
break;
case 2:
if(getCurrentMillis() - currentMillis >= 200) {
// 200ms time for output low has elapsed, proceed to next step
cp = 0; // Last step is done, reset the state for new calls
}
break;
default:
// For anything else, reset the task state to the initials
cp = 0 // Reset the task state to zero so that it accepts new calls
}
}
/*
* Let's say this task will wait for a button press event and will
* trigger the outputTask upon the event occurs
*/
void outputTriggerTask() {
static unsigned char cp = 0;
static unsigned short currentMillis;
switch(cp) {
case 0:
if(isButtonPressed()) { // Platform specific function
// A button press has been detected, debounce first
currentMillis = getCurrentMillis(); // Platform specific function
cp = 1; // Next step, check for the elapsed time
}
else {
break;
}
case 1:
if(getCurrentMillis() - currentMillis >= 50) {
// Check whether the button press is consistent
if(isButtonPressed()) {
// Yes still consistent, handle the button press by triggering the output task
outputTask(0); // Not a periodic call
cp = 2; // Next step is to check whether button is released
}
else {
cp = 0; // Reset the task state
}
}
break;
case 2:
if(isButtonReleased()) { // Platform specific function
currentMillis = getCurrentMillis();
cp = 3;
}
else {
break;
}
case 3:
if(getCurrentMillis() - currentMillis >= 50) {
// Check whether the button release is consistent
if(isButtonReleased()) {
// Yes still consistent, handle the button release if needed
cp = 0; // Reset the task to its initial state
}
}
break;
default:
cp = 0; // Reset to initials
}
}
Scheduler for Time Checking Approach
void main(void) {
systemInit(); // Platform specific function
initMillisTimerWithInterrupt(); // Platform specific function
// maybe some more init functions go here
// Application's infinite scheduler loop
while(1) {
// Now that we use a free running millis timer no need to block the CPU to create a timebase
// Just call tasks sequentially. Each task will know what to do individually
outputTriggerTask(); // Check whether any button press event has occured
outputTask(1); // It is a periodic call for the output task
// Maybe more tasks go here...
}
}

What should I do for stop the loop at the background when I am not pressing the button?

I am new here ,sooo sorry for the mistakes :P.
So whatever. I am trying to do a simple counter circuit with Arduino UNO, a catot 7-segment display and a button. I just want to when I press the button system circle start and takes one footstep. For example 7-segment shows "0" from earlier push, when ı push the button it needs to be "1". But ıdk why its keep counting from background and I couldn't stop it. Then I make some adjustments in my code( btw ı am coding in micro-c for AVR and using AVRDUDES for load my code in Arduino.) and then its stuck at "F" (System should count like 1,2,3,4,5,6,7,8,9,A,b,c,d,E,F). I don't understand why and how can I solve it. Additionally 7 segment led connected with my D port. I want to do B0 pin is input. Then I want to control the B0 pin's value. When B0 pin is HİGH, then i want to program continue.
unsigned char dizi[] = {0x40,0xF9,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0x08,0x03,0x27,0x21,0x06,0x0E};
unsigned int i ;
void main()
{
DDRD = 0xFF ;
DDB0_bit = 0 ;
while(PINB.B0);
{
for(i = 0;i<=15;i++)
{
PORTD = dizi[i] ;
Delay_ms(700);
}
}
}
I just write the code and just ıdk ı hope it work. But it didn't. Idk why and my mind is so blurry ı can't see the error. I hope u can help :D.
What are you using to program your Arduino?
The loop never stops after you press the button because you don't have a stop condition aside from i reaching 15. I'm rusty on Arduino but you could add
if(!(PINB.B0)){ break; }
in the for loop, after the delay to exit the loop when you're not pressing the button.
Your program needs to work like this:
for(;;) { /* program here */ } Microcontroller programs never leave main().
You need to read the button and then debounce it. This should be mentioned in any embedded systems beginner tutorial. Debouncing is mandatory whenever you have a button, or the program will just behave randomly, sometimes missing keyboard presses, other times taking several at once etc.
(The most proper way to do this is to read the button repeatedly from a timer callback, but then you need to write the code for the timer/RTC hardware peripheral driver first.)
Once you have a debounced signal pressed/not pressed, then implement a simple state machine like in this pseudo code:ish C below:
typedef enum
{
NOT_PRESSED,
PRESSED_UPDATE_DISPLAY,
PRESSED_STILL_DISPLAYED,
} simple_state_machine_t;
simple_state_machine_t state = NOT_PRESSED;
...
int index_7seg = 0;
for(;;)
{
/* debounce button */
bool is_pressed = debounced_value;
switch(state)
{
case NOT_PRESSED:
state = is_pressed ? PRESSED_UPDATE_DISPLAY : NOT_PRESSED;
break;
case PRESSED_UPDATE_DISPLAY:
index_7seg++;
if(index_7seg == max_7seg)
{
index = 0;
}
state = is_pressed ? PRESSED_DISPLAYED : NOT_PRESSED;
break;
case PRESSED_DISPLAYED:
state = is_pressed ? PRESSED_DISPLAYED : NOT_PRESSED;
break;
}
PORTD = the7seg_table[index_7seg];
} /* for(;;) */
The PRESSED_UPDATE_DISPLAY state will only get entered when you go from not pressed to pressed, essentially giving you a rising edge trigger through software. That's the only time you should increase the table index.

Trying to find a good way to control servos at different speeds using johnny-five.io

I am currently trying to figure out a configuration in controlling servos connected to Arduinos using Nodebot johnny-five.io hosted on an RPi. My main goal is to make a hexapod from scratch; I don't like the idea of kits because it's all cookie cutter code and parts that you put together and it's more or less a remote controlled car where you didn't learn anything.
I just learned the basics about servos (which I'm selecting servos over stepper motors). And unfortunately, as a default, servo speed cant be controlled via PWM, only position. So the way around this is to create a loop that increments the servo 1 degree (or more) at a time with an X ms delay in the loop until the servo has reached the desired position. Now, this is fine and all if you're only controlling one servo at a time or X amount of servos at a time for moving to one set position to another. But I'm shooting for a fluid motion here; I want one leg to start moving before another leg has stopped. True fluidity in motion, to accomplish this, I would need an infinite loop that would check on input states set by control commands that the API would receive.
The problem here is that while loops are not asynchronous. So, I need to find a way to kick a loop off that sets the different servos at different speed ranges and different positions, and at the end of the loop checks for new input state updates. And I need to do this without creating a memory leak.
One way would be to create a set of dependency scripts that worked asynchronously for each of the servos (3 servos per leg, 6 legs, 18 servos thus 18 mini dependencies), but I'm not sure if that would be too much overhead or put much strain onto the RPi.
Am I overthinking this?
You could create a simple servo class and give each instance its own speed and starting position using an 'update' method. Use a longer delay to have the servo move slower. In the main loop you can continuously check for some input, tell the servos to move if necessary, using the update method.
#include <Servo.h>
class HexapodLegServo
{
Servo servo; // Servo instance
int pos; // Position/angle of the servo
int delay_millis; // 'Delay' between each update
long prev_millis;
int degree_change; // Angle increase each update
int start_pos; // Position to start at
int pin; // Pin servo is connected to
public:
HexapodLegServo (int whichPin, int delayMillis=15, int startPos=0)
{
pin = whichPin;
delay_millis = delayMillis;
start_pos = startPos;
degree_change = 1;
}
void attachToPin()
{
servo.attach(pin);
setStartPos();
}
void setStartPos() // Set initial position of the servo
{
servo.write(start_pos);
pos = start_pos;
}
void update() // Servo sweeps from end to end, and back
{
if (millis()-prev_millis > delay_millis)
{
prev_millis = millis();
servo.write(pos);
pos += degree_change;
if ((pos <= 0) || (pos >= 180))
{
degree_change *= -1; // Start moving in the reverse direction
}
}
}
};
// Main script
const int BUTTON = 4; // Button on pin 4
HexapodLegServo right_leg(9);
HexapodLegServo left_leg(10, 30, 90);
void setup()
{
Serial.begin(9600);
pinMode(BUTTON, INPUT_PULLUP); // Using a button to tell servos when to move
right_leg.attachToPin();
left_leg.attachToPin();
}
void loop()
{
if (digitalRead(BUTTON) == LOW) // If button is pushed (can be any type of input)
{ // update the position of the servos continuously
right_leg.update();
left_leg.update();
}
}

Selectively ignoring parts of a randomly generated sequence of numbers (in C)

I have a question that may be hard to understand -- but I will try my best to explain.
I'm programming the Simon Game in C. This implementation specifically read/writes to a hardware DAQ module that has a 4 LED display, and 4 corresponding toggle switches.
As per the rules of the Game, I've seeded and generated a random sequence of numbers between 0 and 3 (sequence length is arbitrarily 5). In the Game, if the player presses the wrong switch (i.e. blue is shown but you press green), the game ends and restarts.
The way I've set up the Game looks like this:
(I haven't included the code for function "blinkLED" here -- it turns the actual LED on/off.)
void runSimon(void){
int sequence[MAX_SEQ_LEN];
int i;
int count = 0;
// Seeds the random number generator.
srand((unsigned)time(NULL));
// Generate the random LED sequence & store it as an array.
for (i = 0; i < MAX_SEQ_LEN; i++){
sequence[i] = (rand() % NUM_LEDS);
}
// The game begins!
while (continueSuperLoop() == TRUE){
// Loop the game while the sequence length is less than the pre-defined maximum (currently it's 5).
while (count < MAX_SEQ_LEN){
for (i = 0; i <= count; i++){
// Blink the first 'count' LEDs in the sequence, one at a time.
blinkLED(sequence[i], 1, ONE_SEC);
//
//
//THE ISSUE SHOULD BE HERE (!)
//
// Monitors whether or not the player has made a mistake...if so, blink the red LED thrice, then restart the game.
if (digitalRead(sequence[ !i ] == SWITCH_ON)){
blinkLED(LED_1_R, 3, HALF_SEC);
Sleep(3 * ONE_SEC);
continue;
}
// Monitors whether or not the correct switch is being pressed -- waits for it to be released
while (digitalRead(sequence[i]) == SWITCH_ON){}
}
count++;
}
// If 'count' is equal to 'MAX_SEQ_LEN', the green LED blinks 3x to indicate the player has won .
if (count == MAX_SEQ_LEN){
blinkLED(LED_0_G, 3, HALF_SEC);
Sleep(3 * ONE_SEC);
}
}
}
Where I indicated an issue, I'm not sure how the "digitalRead(sequence[ ! i ]" behaves; I need this line to read every switch that's not supposed to be pressed.
I don't think the compiler understands what I'm trying to do here, though -- for example, if the first number in the sequence is 3 (representing the 4th LED), I need to specify that every other number (0, 1, 2) and its corresponding switch should not be pressed.
Would a solution be to store the current number in the sequence, having a set of four TRUE/FALSE flags for each LED, and monitoring the three non-current numbers and their corresp. switches to see if they are pressed?
I'm getting quite frustrated with writing this program. I'm pretty new to programming. Any help is appreciated.
I'm not sure I understand the rules of this game correctly but one thing that jumps out instantly is
digitalRead(sequence[ !i ]
I think you want
!digitalRead(sequence[ i ]
Also, you need to fix your game flow. Right now it's:
1. Light LED.
2. Check if user pressed the right button.
You need to wait for some time before checking a switch or wait for ANY switch to be pressed and see if it's the correct one. So something like this:
1. Light LED.
2. Wait for timeout or ANY switch to be pressed.
3. If timeout: error
4. else: check if switch that was pressed is correct.
In C, ! operator is a unary NOT. When applied to an integer i, it is equivalent to if (i == 0) return 1; else return 0;. Then you are using !i as an index for sequence array, so it will be either sequence[0] or sequence[1], and clearly this is not what you want. Also your == is inside of digitalRead call :)
I would suggest explicitly checking for every other button not to be pressed. Like this:
int isOtherPressed = 0;
for (ledId = 0; ledId < NUM_LEDS; ledId++) {
if (ledId != sequence[i] && digitalRead(ledId) == SWITCH_ON) {
isOtherPressed = 1;
}
}
if (isOtherPressed) {
// restart the game
}
However, I'm suspicious about the whole gameplay you have, but maybe it's just because I don't know how digitalRead works. For example, the way you use continue doesn't seem to stop the game. Maybe you meant break?

how to stop looping and wait until different value received from serial

hi i planning to made a multiple servo controlling with serial as control trigger signal on AVR with C and codevision
but when the trigger is true, the servo running in crazy loop, it back to original position (0 degree) instead of stay on desired position, my tutor give me hint to use "wait ... until" statement with the old data comparison but i'm not found the way to utilize it yet on google
because utilizing break; at the end of the if left the chip freeze until it reset
and the old code(it runs the servo forth and back continously)
while (1)
{
while(UCSRA & (1<<RXC))
{
// Place your code here
//data=UDR;
PORTC=UDR;
data=UDR;
//PORTB=data;
} ;
if (data== 0x0A || data== 0x0B)
{
if (data== 0x0A)
{
old_data=data;
PORTA=0x00;
PORTA.1=1;
movservo0(90,7);
movservo1(15,3);
}
if (data== 0x0B)
{
old_data=data;
PORTA=0x00;
PORTA.1=1;
movservo0(15,3);
movservo1(90,7);
}
}
}
as for movservo0 (another movservo() almost had same code)
void set_servo1(unchar derajat)
{ unchar n;
servo2=1;
delay_us(750);
for(n=0; n<derajat; n++)
{
delay_us(12);
};
servo2=0;
delay_ms(10);
}
void movservo0(unsigned char sudut, unsigned char speed)
{
unchar i;
set_servo1(sudut);
for (i=1;i<=sudut;i+=speed){
set_servo1(i);
delay_ms(100/speed);
}
}
This new code is a bit better.
The top of the while(UCSRA & (1<<RXC)) loop is fine this way. The loop body will only be entered if there is a character to be read. (Although, I'm not sure why you are expecting to read '\n' or vertical tab.)
A minor problem is the way the UDR is read. The act of reading UDR erases the contents. So you should be using
data=UDR;
PORTC=data;
The jumping of the servos appears to be in the moveservo() function. This function always sets the angle to 1 and then gradually increases the angle of the servo until it reaches the desired angle.
setservo() appears to be an attempt to perform PWM to drive a servo, but it doesn't work correctly. To keep the servo at a desired angle, you have to keep switching the pin from 0 to 1 at the correct times, not just once like this function does. Have you looked at the PWM functions of the timers? You just set these up and they run in the background. An alternative is to use a timer to set an interrupt to wake up and toggle the pins as you need.
If you want to do the switching of the pins without interrupts, then you should be using delays in the while(1) loop itself. Just use the setservo() functions to change some variables.
while(1)
{
// read the UART if ready and set the target values
// this part only runs occasionally
while(UCSRA & (1<<RXC))
{
// etc
}
// The rest of the loop body runs every time
// adjust the servo values toward the target values
// use a counter to determine if to adjust during this loop iteration
// e.g., a slow speed counts to a higher number before adjusting
delay(750);
for(int i = 0; i < NUM_INTERVALS; ++i)
{
// decide whether to set pins to 1 or 0 based on the servo values
delay(INTERVAL);
}
}
I don't know about your particular servos, but they typically have a period where most of the time the pin is 0, and then a short time in the period where the pin is 1. You will need to adjust NUM_INTERVALS and INTERVAL and 750 to add up to the correct length of time.
There is so much wrong with this snippet, it is hard to start. It is difficult to say why the servo is moving, as it is only ever "moved" to the same value every time. (Unless, you have omitted some code that sets it to some other value.)
Typically, when receiving UART, the processor should wait until the character is received. This is accomplished by this
while(UCSRA & (1<<RXC) == 0);
Note the ; creating an empty body of the while loop. This is probably what your tutor meant. When the flag is set, then the loop exits and the data is ready to be read.
while(UCSRA & (1<<RXC) == 0);
data = UDR;
Next, you have a block which looks like you meant to be part of a while loop, but it isn't. The body of the loop is the single statement abbove it. The block gets executed every time.
{
if(data=0x0a)
{
olddata=data;
movservo0(90,7); //move servo to certain degree
}
}
Another error is the condition in the if statement. It looks like you are trying to test if data is 0x0A, but that is not what is happening. Instead, you set data to be 0x0A, and then execute the inner part every time. The condition you probably want is if(data == 0x0A). Note the == instead of =.
So your code is equivalent to
while(1)
{
while(ucsra & (1<<RXC)) data=udr; // maybe read UDR into data
data=0x0a; // set data anyway
olddata=data;
movservo0(90,7); //move servo to certain degree
}
Again, for the jumping servo, I suspect some code that is omitted here that is also runs every time. Or else, the moveservo() function has a problem itself.

Resources